[TOC]
# 策略模式
定义一系列的算法,把它们一个个的封装起来,并且使它们可以相互替换。目的就是算法的使用和算法的实现分离出来。
由两部分组成:
- 策略类:封装了具体的算法,并负责具体的计算过程
- 环境类:接受客户的请求,随后把请求委托给某一个策略类
## 面向对象的实现
```javascript
var S = function(){};
S.prototype.calculate = function(salary){
return salary * 4;
}
var A = function(){};
A.prototype.calculate = function(salary){
return salary * 3;
}
var B = function(){};
B.prototype.calculate = function(salary){
return salary * 2;
}
var Bouns = function(){
this.salary = null;
this.strategy = null;
}
Bouns.prototype.setSalary = function(salary){
this.salary = salary
}
Bouns.prototype.setStrategy = function(strategy){
this.strategy = strategy;
}
Bouns.prototype.getBouns = function(){
return this.strategy.calculate(this.salary);
}
var bouns = new Bouns();
bouns.setSalary(1000);
bouns.setStrategy(new B()); // 设置策略对象
bouns.getBouns();// 输出
```
## JavaScript中的实现
```javascript
var Strategy = {
S: function(salary){
return salary * 4;
},
A: function(salary){
return salary * 3;
},
B: function(salary){
return salary * 2;
}
};
var getBouns = function(strategy, salary){
return Strategy[strategy](salary);
}
getBouns('B', 1000); // 2000
```
## 多态在策略模式中的体现
环境类并没有计算的能力,而是将计算委托给了策略类,会返回不同的计算结果,也正是多态的表现,也是“它们可以相互替换”的目的。
## 更广义的“算法”
策略模式可以用来封装一系列的“业务规则”,只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们。比如表单校验。
## 表单校验
```javascript
var strategies = {
isNonEmpty: function(value, errorMsg){
....
},
minLength: function(value, length, errorMsg){
....
},
isMobile: function(value, errorMsg){
...
}
};
var Validator = function(){
this.cache = [];
};
Validator.prototype.add = function(dom, rule, errorMsg){
var ary = [rule];
this.cache.push(function(){
var strategy = ary.shift();
ary.unshift(dom.value);
ary.push(errorMsg);
return strategies[strategy].apply(dom, ary);
});
}
Validator.prototype.start = function(){
for(var i=0, validatorFunc; validatorFunc = this.cache[i++]){
var msg = validatorFunc();
if(msg){
return msg;
}
}
}
var validatorFunc = function(){
var validator = new Validator(); // 创建一个对象
validator.add(...);
var errorMsg = validator.start(); // 获取校验结果
}
var registerForm = document.getElementById('form');
registerForm.onsubmit = function(){
var errorMsg = validatorFunc();
if(errorMsg){
return false;
}
}
```
## 策略模式的优缺点
1. 避免多重条件选择语句
2. 将算法独立在策略类中,使得它们易于切换、易于理解、易于扩展
3. 策略类可以用在系统的其它地方中
4. 策略类可以利用组合和委托来让环境类拥有执行算法的能力,这也是继承的一种更轻便的替代方案