Definition
The Strategy pattern
is a common and effective design pattern. It refers to defining a set of algorithms, encapsulating them one by one, and making them interchangeable. The essence of the Strategy pattern
is to separate the use of algorithms from their implementation. A basic strategy pattern
has two parts.
- a set of policy classes that encapsulate the specific algorithm inside and are responsible for its concrete implementation.
- an environment class
Context
, which accepts requests from clients and delegates them to a particular policy class.
Advantages and disadvantages
The Strategy pattern
has the following advantages.
- Uses techniques such as
combination
,delegation
, andpolymorphism
to effectively avoid multiple conditional selection statements. - Provides perfect support for the
open-close
principle, and is easy to understand and extend using policy branching functions. - The
combination
,delegation
approach also givesContext
the basic ability to execute algorithms. - Reusability is relatively high.
The disadvantages of the Strategy pattern
are not so obvious, mainly in that the application needs to maintain more policy objects, but essentially the advantages outweigh the disadvantages.
Example
In Javascript
, functions are objects themselves as first-class citizens, so we use objects to implement the Strategy Pattern
.
// part 1
var strategies = {
S: function(salary) {
return salary * 4;
},
A: function(salary) {
return salary * 3;
},
B: function(salary) {
return salary * 2;
},
}
// part 2
var calculateBouns = function(level, salary) {
return strategies[level](salary);
};
console.log(calculateBouns('S', 2000));
console.log(calculateBouns('A', 800));
Scenarios
Form validation
In daily form interaction, we will encounter various input items bound to the corresponding form validation rules, if each input item one by one to write the corresponding rules will be time-consuming and redundant, we can use strategy pattern
to modify.
var strategies = {
isNonEmpty(value, errorMsg) {
if(value === '' || value == null) {
return errorMsg;
}
},
minLength(value, length, errorMsg) {
if(value.length < length) {
return errorMsg;
}
},
isMobile(value, errorMsg) {
if(! /1[3][5][8][0-9]{9}$/.test(value)) {
return errorMsg;
}
},
}
After completing the rule mapping table for the form, create a new Validator
class for rule validation. The Validator
class here acts as a Context
, responsible for receiving user requests and delegating them to strategies
to match the corresponding rules.
var Validator = function() {
this.cache = [];
}
Validator.prototype.add = function(value, rule, errorMsg) {
var arr = rule.split(':');
this.cache.push(
function() {
var stratery = arr.shift();
arr.unshift(value);
arr.push(errorMsg); // [44, "isMobile", 'phone number not in correct format']
return strategies[stratery].apply(this, arr)
}
)
}
Validator.prototype.start = function(value, rule, errorMsg) {
for(let i = 0; i < this.cache.length; i++) {
var validator = this.cache[i];
var msg = validator();
if(msg) {
return msg
}
}
}
// Use
var validator = new Validator();
validator.add('13136199370', 'isMobile', 'Phone number is not in correct format');
validator.add('12', 'minLength: 6', 'Password length cannot be less than 6 digits');
var errMsg = validator.start();
console.log(errMsg);