“This is the 10th day of my participation in the August More Text Challenge. For details, see: August More Text Challenge.”
preface
At the top end of the interview, often encounter some questions about design patterns, each time the answer is not ideal. Coincides with the more challenging activities in August, I am prepared to spend a month to get a good understanding of design patterns, so as to increase my confidence for the interview.
In the last installment of the article details what is a strategic mode and how to achieve a simple strategic mode, the specific can see “interview confidence” – design mode of strategic mode (I) | August more text challenge.
The strategy pattern implemented in the last article was implemented in the form of classes, which simulate the implementation of some traditional object-oriented languages and are a bit too codiously coded. This article introduces a simpler and more straightforward way to implement a policy pattern.
Policy patterns in JavaScript
In JavaScript, functions are objects, so it is simpler and more straightforward to define policies as functions.
Const Strategies = {"S": (salary) => {return salary * 0.2; }, "A": (salary) => {return salary * 0.1; }, "B": (salary) => { return salary * 0; }, "C": (salary) => {return salary * -0.1; }}Copy the code
Similarly, the environment class is not necessarily created as a class, but as a function.
const calculateBonus = (level,salary) =>{ return strategies[ level ]( salary ); }; console.log( calculateBonus( 'S', 20000 ) ); // Output: 4000 console.log(calculateBonus('A', 10000)); // Output: 1000Copy the code
So the amount of code is not a lot less, the structure is clear. This policy pattern can be referred to as a functional form of the policy pattern.
There are more than just algorithms in policy
Strategy pattern: Define a set of algorithms, encapsulate them one by one, and make them interchangeable.
By definition, policy patterns are used to encapsulate algorithms. But the strategy pattern is overused only to encapsulate algorithms.
In practical development, the meaning of the algorithm can be spread so that the policy pattern can also be used to encapsulate a set of “business rules.” As long as the goals of these business rules are consistent and can be substituted, they can be encapsulated in a policy pattern.
Take a very common example of implementing form validation using the policy pattern.
Let’s define the policy group for form validation.
Const Strategies = {isNonEmpty: function (value, errorTip) {if (value === "") {return errorTip; }}, minLength: function (value, length, errorTip) {return errorTip; }}, isMobile: function (value, errorTip) {// If (! /(^1[3|5|8][0-9]{9}$)/.test(value)) { return errorTip; }}};Copy the code
The next step is to implement a Validator class as the environment class in the policy pattern, responsible for receiving requests from users and delegating them to the Strategies Policy group object. Before implementing, imagine how the user sends a request to the Validator class.
Create a Validator object by executing new Validator. Add the Validator to add some validation rules. Then execute validator.check to start validation.
Add (loginForm. Password, 'minLength:6', 'Password length cannot be less than 6'); const errorTip = validator.check(); // Obtain the verification resultCopy the code
LoginForm. Password is the DOM element of the password input box. MinLength :6 is a string separated by colons. The minLength before the colon represents the policy selected by the customer, and the number 6 after the colon represents some of the parameters required in the verification process. MinLength :6 indicates that loginForm. Password Indicates that the minimum length of value in the password input box is 6. If the string does not contain colons, no additional parameter information is required during the verification. The third parameter is the error message returned if the check fails.
Let’s implement the Validator class as envisioned above.
class Validator { constructor() { this.rule = []; } add(dom, rule, errorTip) {const param = rule-.split (':'); This.rule. Push (function () {// wrap the validation step in an empty function and put in rule const strategy = param.shift(); // Select strategy param.unshift(dom.value); // Select strategy param.unshift(dom.value); Param.push (errorTip); // Add the input value to the parameter list. Return strategies[strategy].apply(dom, param); }); } check() { for (let i = 0, validatorFunc; validatorFunc = this.cache[i++];) { const errorTip = validatorFunc(); If (errorTip) {// If there is an exact return value, the verification does not pass. Return errorTip; }}}}Copy the code
This is how you end up using the environment class Validator
const validataFunc = function () { const validator = new Validator(); / / create a validator object / * * * * * * * * * * * * * * * add some validation rules * * * * * * * * * * * * * * * * / validator. Add (loginForm. The userName, 'isNonEmpty', 'Username cannot be empty '); Add (loginForm. Password, 'minLength:6', 'Password length cannot be less than 6'); Validator. add(loginForm. PhoneNumber, 'isMobile', 'Incorrect mobile number format '); var errorTip = validator.check(); Return errorTip; } const loginForm = document.getelementById ('loginForm'); loginForm.onsubmit = function () { const errorTip = validataFunc(); If (errorTip) {console.log(errorTip); return false; // Block form submission}};Copy the code
Advantages and disadvantages of the strategic pattern
Advantages:
-
The strategy pattern can effectively avoid multiple conditional selection statements by using techniques and ideas such as composition, delegation and polymorphism.
-
The policy pattern provides perfect support for the open-close principle, encapsulating algorithms in separate policies, making them easy to switch, easy to understand, and easy to extend.
-
Algorithms in the policy pattern can also be reused elsewhere in the system, avoiding a lot of duplicated copy-and-paste work.
-
Using composition and delegation in the policy pattern to give the environment class the ability to execute the algorithm is also a lighter alternative to inheritance.
Disadvantages:
-
While using the policy pattern can add a lot of policy classes or policy objects to your program, it is much better than piling up logic on environment classes.
-
To use the policy pattern, you must understand all the policies and the differences between them so that you can choose an appropriate one. For example, if we want to choose a suitable travel route, we must first understand the details of the choice of plane, bullet train, bus and so on. At this point, the policy group exposes all of its implementations to other classes, which violates the least knowledge principle.
The idea of polymorphism is at the heart of the strategy pattern
The idea of polymorphism: The idea of polymorphism is to separate what is done from who does it and how it is done, that is, things that do not change from things that may change.
For example, in the example of validating a form, what rules to use to validate the form (what to do) are encapsulated in the environment class Validator, and how to validate (who does it and how to do it) is encapsulated in the policy group Strategies.
Adding different validation rules to the environment Validator and then validating the form will produce different results that reflect the definition of polymorphism.
What polymorphism means: The same operation on different objects can produce different interpretations and different execution results.