javascript Design Pattern Strategy Pattern Learning Notes

  • 2021-07-21 07:03:35
  • OfStack

1. Understand policy patterns in javascript

The definition of a policy pattern is to define a series of algorithms, encapsulate them one by one, and make them interchangeable.

The advantages of using policy pattern are as follows:

Advantages:

1. The policy pattern can effectively avoid many if conditional statements by using the techniques and ideas such as combination and delegation.

2. Policy patterns provide an open-closed principle that makes code easier to understand and extend.

3. Code in policy mode can be reused.

1. Calculate bonus using strategy mode;

The following demo is what I saw in the book, but it doesn't matter, we just want to understand the use of the strategy mode, we can use the strategy mode to calculate the bonus problem;

For example, the company's year-end award is assessed according to the salary and performance of employees. For those with performance of A, the year-end award is 4 times of salary, for those with performance of B, the year-end award is 3 times of salary, and for those with performance of C, the year-end award is 2 times of salary; Now we use the 1-style coding method to write the code as follows:


var calculateBouns = function(salary,level) {
  if(level === 'A') {
    return salary * 4;
  }
  if(level === 'B') {
    return salary * 3;
  }
  if(level === 'C') {
    return salary * 2;
  }
};
//  The call is as follows: 
console.log(calculateBouns(4000,'A')); // 16000
console.log(calculateBouns(2500,'B')); // 7500

The first parameter is salary and the second parameter is grade.

The code has the following disadvantages:

The calculateBouns function contains a number of if-else statements.

The calculateBouns function lacks elasticity. If there is an D level, then we need to add an if statement to judge the level D in the calculateBouns function;

The reusability of the algorithm is poor, if there are similar algorithms in other places, but the rules are not 1, so our codes cannot be universal.

2. Refactoring code using combinatorial functions

Combination function is to encapsulate various algorithms into a small function. For example, if the grade is A, it encapsulates a small function, if the grade is B, it also encapsulates a small function, and so on; The following code:


var performanceA = function(salary) {
  return salary * 4;
};
var performanceB = function(salary) {
  return salary * 3;
};
    
var performanceC = function(salary) {
  return salary * 2
};
var calculateBouns = function(level,salary) {
  if(level === 'A') {
    return performanceA(salary);
  }
  if(level === 'B') {
    return performanceB(salary);
  }
  if(level === 'C') {
    return performanceC(salary);
  }
};
//  Call the following 
console.log(calculateBouns('A',4500)); // 18000

The code seems to have improved a little, but it still has the following shortcomings:

The calculateBouns function may become larger and larger, such as when the D level is increased, and it lacks elasticity.

3. Refactoring code using policy patterns

Policy pattern refers to defining a series of algorithms, encapsulating them one by one, separating the unchanging part from the changing part, and actually separating the use and implementation of algorithms; The use of the algorithm is unchanged, and the calculated bonus is obtained according to a certain algorithm, while the realization of the algorithm corresponds to different performance rules according to performance;

A program based on policy pattern consists of at least two parts. The first part is a group of policy classes, which encapsulate specific algorithms and take charge of specific calculation processes. The second part is the environment class Context, which receives the request from the client and then delegates the request to some 1 policy class. We first use traditional object-oriented to achieve;

The following code:


var performanceA = function(){};
performanceA.prototype.calculate = function(salary) {
  return salary * 4;
};   
var performanceB = function(){};
performanceB.prototype.calculate = function(salary) {
  return salary * 3;
};
var performanceC = function(){};
performanceC.prototype.calculate = function(salary) {
  return salary * 2;
};
//  Bonus category 
var Bouns = function(){
  this.salary = null;  //  Original wage 
  this.levelObj = null; //  Policy Objects for Performance Ratings 
};
Bouns.prototype.setSalary = function(salary) {
  this.salary = salary; //  Save the original salary of employees 
};
Bouns.prototype.setlevelObj = function(levelObj){
  this.levelObj = levelObj; //  Set up policy objects corresponding to employee performance levels 
};
//  Number of bonuses obtained 
Bouns.prototype.getBouns = function(){
  //  Delegate the operation of calculating bonus to the corresponding policy object 
  return this.levelObj.calculate(this.salary);
};
var bouns = new Bouns();
bouns.setSalary(10000);
bouns.setlevelObj(new performanceA()); //  Setting Policy Objects 
console.log(bouns.getBouns()); // 40000
    
bouns.setlevelObj(new performanceB()); //  Setting Policy Objects 
console.log(bouns.getBouns()); // 30000

As the above code uses policy pattern to reconstruct the code, you can see that the code responsibilities are updated clearly and the code becomes clearer.

4. Policy Mode for Javascript Release


// The code is as follows: 
var obj = {
    "A": function(salary) {
      return salary * 4;
    },
    "B" : function(salary) {
      return salary * 3;
    },
    "C" : function(salary) {
      return salary * 2;
    } 
};
var calculateBouns =function(level,salary) {
  return obj[level](salary);
};
console.log(calculateBouns('A',10000)); // 40000

You can see that the code is simpler and clearer;

Policy pattern refers to defining 1 series of algorithms and encapsulating them, but policy pattern not only encapsulates algorithms, but also encapsulates 1 series of business rules. As long as these business rules have goal 1, we can use policy pattern to encapsulate them;

Form validation

For example, we often validate forms, such as registering the login dialog box, and we need to validate before logging in: For example, there are the following logics:

User name cannot be empty

Password length cannot be less than 6 digits.

The mobile phone number must conform to the format.

For example, the HTML code is as follows:


<form action = "http://www.baidu.com" id="registerForm" method = "post">
    <p>
      <label> Please enter a user name: </label>
      <input type="text" name="userName"/>
    </p>
    <p>
      <label> Please enter your password: </label>
      <input type="text" name="password"/>
    </p>
    <p>
      <label> Please enter your mobile phone number: </label>
      <input type="text" name="phoneNumber"/>
    </p>
</form>

We normally write the form verification code as follows:


var registerForm = document.getElementById("registerForm");
registerForm.onsubmit = function(){
  if(registerForm.userName.value === '') {
    alert(' User name cannot be empty ');
    return;
  }
  if(registerForm.password.value.length < 6) {
    alert(" Password length cannot be less than 6 Bit ");
    return;
  }
  if(!/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)) {
    alert(" The mobile phone number format is incorrect ");
    return;
  }
}


However, writing code like this has the following disadvantages:

1. registerForm. onsubmit function is relatively large, and the code contains many if statements;

2. The registerForm. onsubmit function lacks flexibility. If we add a new validation rule or want to change the length validation of passwords from 6 to 8, we must change the internal code of registerForm. onsubmit function. Violation of the open-closed principle.

3. The reusability of the algorithm is poor. If another form is added to the program, this form needs to be verified similarly, then we may need to copy the code again;

Next, we can use the policy pattern to reconstruct the form validation;

In the first step, we will encapsulate the policy object first; The following code:


var strategy = {
  isNotEmpty: function(value,errorMsg) {
    if(value === '') {
      return errorMsg;
    }
  },
  //  Limit minimum length 
  minLength: function(value,length,errorMsg) {
    if(value.length < length) {
      return errorMsg;
    }
  },
  //  Mobile phone number format 
  mobileFormat: function(value,errorMsg) {
    if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
      return errorMsg;
    }
  } 
};

Next, we are going to implement the Validator class, and the Validator class here acts as Context, which is responsible for receiving the user's request and delegating it to the strategy object, as follows:


var Validator = function(){
  this.cache = []; //  Preservation of validation rules 
};
Validator.prototype.add = function(dom,rule,errorMsg) {
  var str = rule.split(":");
  this.cache.push(function(){
    // str  Returns the  minLength:6 
    var strategy = str.shift();
    str.unshift(dom.value); //  Put input Adj. value Add to parameter list 
    str.push(errorMsg); //  Put errorMsg Add to parameter list 
    return strategys[strategy].apply(dom,str);
  });
};
Validator.prototype.start = function(){
  for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {
    var msg = validatorFunc(); //  Begin to be effective   And get the return information after validation 
    if(msg) {
      return msg;
    }
  }
};

The Validator class here acts as the Context and is responsible for receiving the user's request and delegating it to the strategys object. In the above code, we first create an Validator object, and then add some validation rules to the validator object through the validator. add method, which receives three parameters, as follows:

validator. add (registerForm. password, 'minLength: 6', 'Password length cannot be less than 6 bits');

registerForm. password is the dom node of the input input box;

minLength: 6: is a string separated by a colon. minLength before the colon represents the strategys object selected by the customer, and the number 6 after the colon represents the parameters that must be verified in the validation process. minLength: 6 means validation of registerForm. password. The minimum length of value in this text input box is 6 digits; If the string does not contain colons, it means that no additional validation information is needed in the validation process;

The third parameter is the error message returned when the validation fails;

After we have added 1 series of validation rules to the validator object, we call the validator. start () method to start validation. If validator. start () returns an errorMsg string as the return value, the validation failed, and the registerForm. onsubmit method is required to return false to prevent form submission. Let's look at the initialization code as follows:


var validateFunc = function(){
  var validator = new Validator(); //  Create 1 A Validator Object 
  /*  Add 1 Some effective rules  */
  validator.add(registerForm.userName,'isNotEmpty',' User name cannot be empty ');
  validator.add(registerForm.password,'minLength:6',' Password length cannot be less than 6 Bit ');
  validator.add(registerForm.userName,'mobileFormat',' The mobile phone number format is incorrect ');

  var errorMsg = validator.start(); //  Obtain effective results 
  return errorMsg; //  Return the validation result 
};
var registerForm = document.getElementById("registerForm");
registerForm.onsubmit = function(){
  var errorMsg = validateFunc();
  if(errorMsg){
    alert(errorMsg);
    return false;
  }
}

The following is all the code as follows:


var strategys = {
  isNotEmpty: function(value,errorMsg) {
    if(value === '') {
      return errorMsg;
    }
  },
  //  Limit minimum length 
  minLength: function(value,length,errorMsg) {
    if(value.length < length) {
      return errorMsg;
    }
  },
  //  Mobile phone number format 
  mobileFormat: function(value,errorMsg) {
    if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {
      return errorMsg;
    }
  } 
};
var Validator = function(){
  this.cache = []; //  Preservation of validation rules 
};
Validator.prototype.add = function(dom,rule,errorMsg) {
  var str = rule.split(":");
  this.cache.push(function(){
    // str  Returns the  minLength:6 
    var strategy = str.shift();
    str.unshift(dom.value); //  Put input Adj. value Add to parameter list 
    str.push(errorMsg); //  Put errorMsg Add to parameter list 
    return strategys[strategy].apply(dom,str);
  });
};
Validator.prototype.start = function(){
  for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {
    var msg = validatorFunc(); //  Begin to be effective   And get the return information after validation 
    if(msg) {
      return msg;
    }
  }
};

var validateFunc = function(){
  var validator = new Validator(); //  Create 1 A Validator Object 
  /*  Add 1 Some effective rules  */
  validator.add(registerForm.userName,'isNotEmpty',' User name cannot be empty ');
  validator.add(registerForm.password,'minLength:6',' Password length cannot be less than 6 Bit ');
  validator.add(registerForm.userName,'mobileFormat',' The mobile phone number format is incorrect ');

  var errorMsg = validator.start(); //  Obtain effective results 
  return errorMsg; //  Return the validation result 
};
var registerForm = document.getElementById("registerForm");
registerForm.onsubmit = function(){
  var errorMsg = validateFunc();
  if(errorMsg){
    alert(errorMsg);
    return false;
  }
};

As above, we can see the benefits by using the policy mode to write the form verification code. We have completed the validation of one form through add configuration; In this way, the code can be used as a component and can be called at any time. When modifying the form verification rules, it is also very convenient and can be called by passing parameters;

Add a variety of validation rules to a text input box. As we can see from the above code, we only give the input box only one validation rule. For example, we can only validate whether the input box is empty, validator. add (registerForm. userName, 'isNotEmpty', 'User name cannot be empty'); But if we want to verify that the input box is empty and that the length of the input box is not less than 10 bits, we expect to pass parameters like this:

validator. add (registerForm. userName, [{strategy: 'isNotEmpty', errorMsg: 'User name cannot be empty'}, {strategy: 'minLength: 6', errorMsg: User name cannot be less than 6 digits'}])

We can write the following code:


var performanceA = function(salary) {
  return salary * 4;
};
var performanceB = function(salary) {
  return salary * 3;
};
    
var performanceC = function(salary) {
  return salary * 2
};
var calculateBouns = function(level,salary) {
  if(level === 'A') {
    return performanceA(salary);
  }
  if(level === 'B') {
    return performanceB(salary);
  }
  if(level === 'C') {
    return performanceC(salary);
  }
};
//  Call the following 
console.log(calculateBouns('A',4500)); // 18000
0

Note: The above codes are all done according to the book. They all see the code of the book. The most important thing is to understand the implementation of the policy mode. For example, the above form verification function is encapsulated in this way. We usually use jquery plug-in form verification code to be encapsulated in this way, so we can also use this way to encapsulate forms and other learning in the future;


Related articles: