JavaScript Design Pattern - strategy pattern

Keywords: Front-end less Attribute Javascript Programming

The strategy pattern is the behavior pattern in JavaScript Design pattern.

Definition:

Define a series of algorithms, encapsulate them into strategy classes (Methods), and then separate the invariant part and the changing part, and these algorithms can replace each other

Vernacular explanation:

In fact, the so-called policy pattern is that values execute different methods according to different policies, which is very similar to if else branch judgment, but the policy pattern is used to solve multiple conditional judgment statements.

Use scenario:

Requirements:

At the end of the year, a company decides to issue the year-end bonus in advance, but there are certain rules for the calculation of the year-end bonus, and the amount of the year-end bonus is closely related to the performance appraisal; therefore, the year-end bonus plan of a company is as follows:

For employees whose performance appraisal is S, the year-end bonus is 4 times of their monthly salary;

For employees with performance assessment of A, the year-end bonus is three times of their monthly salary;

For employees whose performance appraisal is B, the year-end bonus is twice of their monthly salary;

See here to let you start to write programs. Generally, most of the code is as follows:

    function calculateBonus(level,salary){
        if(level === 'S'){
            return salary*4;
        }
        
        if(level === 'A'){
            return salary*3
        }

        if(level === 'B'){
            return salary*2
        }
    }

    console.log(calculateBonus("S",14000));  //56000
    console.log(calculateBonus("A",10000)); //30000
    console.log(calculateBonus("B",5000));  //10000

There is no problem for the above code to solve the current requirements, but from the perspective of programming, the above code can be optimized; because the method is relatively large, there are many branch judgments, and lack of flexibility; if the year-end bonus scheme is changed, what about adding a C scheme? Is it necessary to add branch judgment to the method? This violates the principle of opening and closing;

Optimization:

    var strategies  = {
        "S":function(salary){
            return salary*4
        },
        "A":function(salary){
            return salary*3;
        },
        "B":function(salary){
            return salary*2
        }
    }

    var calculateBonus =function(level,salary){
        return strategies[level](salary);
    } 
    console.log(calculateBonus("S",14000));  //56000
    console.log(calculateBonus("A",10000));  //30000
    console.log(calculateBonus("B",5000));   //10000

After optimizing the above code, the above is to use the policy mode to modify the code. We can see that we have defined a policy object, and then calculateBonus can calculate the amount of year-end bonus according to the level and salary passed in by the user. After the transformation, the code structure becomes more concise.

In web development, form submission is required for login page registration, login and other functions; however, in the process of submission, verification and filtering must be carried out, and those that do not conform to the verification rules cannot be submitted directly; before learning the design mode, our verification may be the same as the above multiple if branch judgment, and now we use the policy mode to implement. Now a form verification:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
        <form action="http:// xxx.com/register" id="registerForm" method="post">
            //Please enter the user name: < input type = "text" name = "username" / >
            //Please enter the password: < input type = "text" name = "password" / >
            //Please input the mobile number: < input type = "text" name = "phonenumber" / >
            <button>Submission</button>
        </form>
</body>
<script>
        // Define policy algorithm verification rules
        var strategies = {
        isNonEmpty: function( value, errorMsg ){
            if ( value === '' ){
                return errorMsg;
            }
        },
        minLength: function( value, length, errorMsg ){
            if ( value.length < length ){
                return errorMsg;
            }
        },
        isMobile: function( value, errorMsg ){
            if ( !/(^1[3|5|8][0-9]{9}$)/.test( value ) ){
                return errorMsg;
            }
        }
    };
    //Validator class  
    var Validator = function(){
        // Save verification rules
        this.cache = [];
    };
    //How to add validation rules
    Validator.prototype.add = function( dom, rules ){
        var self = this;
        for ( var i = 0, rule; rule = rules[ i++ ]; ){
            (function( rule ){
                //Split the value of the strategy attribute in the validation rule object
                var strategyAry = rule.strategy.split( ':' );
                var errorMsg = rule.errorMsg;
                self.cache.push(function(){
                    //Load the first value of the strategy attribute in the validation rule object back into strategy
                    var strategy = strategyAry.shift();
                    //Composition parameter
                    strategyAry.unshift( dom.value );
                    //Assembly parameters
                    strategyAry.push( errorMsg );
                    //Find the execution method of the policy object and install it into the cache variable
                    return strategies[ strategy ].apply( dom, strategyAry );
                });
                console.log(strategyAry);
            })( rule )
        }
    };
    //Start verification method
    Validator.prototype.start = function(){
        for ( var i = 0, validatorFunc; validatorFunc = this.cache[ i++ ]; ){
             //Check the execution method of cyclic cache
            var errorMsg = validatorFunc();
            //If errorMsg is returned in the execution policy object method, the method has reported an error (failed the validation rule).
            if ( errorMsg ){
                return errorMsg;
            }
        }
    };

    //Call validation
    var registerForm = document.getElementById( 'registerForm' );
    //Define methods to add verification rules by customization
    var validataFunc = function(){
        //Instanced object
        var validator = new Validator();
        //Custom add verification rule
        validator.add( registerForm.userName, [{
            strategy: 'isNonEmpty',
            errorMsg: 'User name cannot be empty'
        }, {
            strategy: 'minLength:6',
            errorMsg: 'User name length cannot be less than 10 digits'
        }]);
        validator.add( registerForm.password, [{
            strategy: 'minLength:6',
            errorMsg: 'Password length cannot be less than 6 digits'
        }]);
        //Call method loop to perform verification
        var errorMsg = validator.start();
        return errorMsg;
    }
    //Click Submit button (submit event)
    registerForm.onsubmit = function(){
        //Perform the above customized verification method
        var errorMsg = validataFunc();
        //If errorMsg exists, it means the verification fails
        if ( errorMsg ){
            alert ( errorMsg );
            return false;
        }

    };
</script>
</html>

We can solve the problem of large-scale repetition of if else judgment in form verification through policy mode. The above code annotation I have given is very detailed. To learn the design mode, we must go to detail the code and learn the ideas. Anyway, one of the main ideas of policy mode is to define a series of algorithms, then pass in parameters, and perform different calculations according to different parameters. Rule of law;

 

Advantages and disadvantages:

Advantages:

1. By using combination, delegation and polymorphism techniques and ideas, multiple conditional choice statements can be avoided.

2. The algorithm is encapsulated in an independent strategy class, which makes it easy to switch, understand and expand.

3. The policy mode can be reused in other parts of the system, so as to avoid duplicate copy and paste work;

Disadvantages:

1. Many policy classes or policy objects will be added to the program;

2. To use the strategy class, you must know all the algorithm of the strategy class clearly, otherwise you don't know how to choose.

Posted by yarub on Fri, 18 Oct 2019 00:55:18 -0700