策略模式

定义一系列算法,把它们封装起来,并且使它们可以相互替换。其至少有两部分组成

  • 策略类,负责各个具体的算法,负责具体计算过程
  • 环境类Context, 接收用户请求,负责委托给策略类

简例

计算年终奖,有多种方案,使用各种策略类实现

1
2
3
4
5
6
7
8
9
10
class PerformanceA {
cal (salary) {
return salary * 4
}
}
class PerformanceB {
cal (salary) {
return salary * 3
}
}

奖金对应多种绩效,但是规则都是一样的,接收用户的设置和请求,并委托给策略:

1
2
3
4
5
6
7
8
9
10
11
class Bonus {
setSalary (salary) {
this.salary = salary
}
getPerformance (perform) {
this.performance = perform
}
getBonus(){
return this.this.performance.cal(this.salary)
}
}

这样,我们的Bonus类,并不负责计算,而将计算委托给传入的Performance类进行,做了好的解耦。

1
2
3
4
var bonus = new Bonus();
bonus.setSalary( 10000 );
bonus.getPerformance( new performanceS() ); // 设置策略对象
console.log( bonus.getBonus() ); // 输出:40000

实现

总的来说,我们需要两个东西来实现JavaScript策略模式:策略集和策略管理

其实最好理解的就是表单验证了,针对各种表单,我们可以为其设置一个验证的策略集合:

1
2
3
4
5
6
7
8
9
var validateRules = {
isNotEmpty (value, errMsg) {
return value === ‘’ ? errMsg : ’’
},
minLength (value, length, errMsg) {
return value.length < length ? errMsg : ‘’
}
}

然后有个Validator管理策略

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
class Validator {
contructor (){
this.rules = []
}
add (target, rules) {
rules = rules.map(rule => {
const ruleDetail = rule.rule.split(‘:’)
const [fnName, …params] = ruleDetail
const ruleFn = validateRules[fnName]
return () => {
return ruleFn(target.value, …params)
}
})
this.rules = this.rules.concat(rules)
}
validate () {
const msg = this.rules.some(fn => fn())
if (msg) {
return msg
}
}
}

可以通过add方法添加规则,通过validate执行validate。实现了我们的策略管理。

其他语言实现

策略模式(Strategy):定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化,不会影响使用算法的客户

  1. Strategy类,定义所有支持算法的接口
  2. ConcreteStrategy,继承Strategy,实现具体算法或行为
  3. Context 类,维护算法Strategy类的引用

最终:

1
2
3
4
5
ctx = new Context(new ConcreteStrategyA())
ctx.count()
ctx = new Context(new ConcreteStrategyB())
ctx.count()

总结

  1. 策略模式是指定义一些列算法,以相同的方式调用这些算法,减少了算法使用和算法类之间的耦合。
  2. 使用Strategy可以有效的消除if,switch这种条件语句,避免大量的判断,更加便于理解
  3. 算法可重用
  4. 在js中其实并不明显,被各类函数直接代替