JavaScript设计模式三(策略模式)
策略模式定义
定义一系列算法,把他们一个个封装起来,并且使他们相互替换
我们可以先看一个例子
策略模式计算年终奖
大家知道年终奖的发放是和工资基数和年终考评来计算的,例如A是4个月工资,B是3个月工资,C是2个月工资。
1、最初的代码实现
var calculateBonus = function(level, salary) {
if (level === 'A') {
return salary*4;
}
if (level === 'B') {
return salary*3;
}
if (level === 'C') {
return salary*2;
}
}
使用方法:
calcaluteBonus('B', 10000)
这段代码平常我们见到的很多,但是它有着明显的缺点
- 函数很杂,随着业务逻辑的增加,这个函数会越来越大
- 缺乏弹性,例如我们A的考评变成5倍,或者增加D的考评,必须要去修改这个函数,这里是违反了开发-封闭原则
- 算法不存在复用性,例如我们需要再另外一个函数中使用这些算法,需要重新再写一遍
2、利用组合函数重构代码
简单来解释,就是把那些算法封装到一个个函数里面。
var algorithmA = function(salary) {
return salary*4;
}
var algorithmB = function(salary) {
return salary*3;
}
var algorithmC = funtion(salary) {
return salary*2;
}
var calculateBonus = function(level, salary) {
if (level === 'A') {
return algorithmA(salary);
}
if (level === 'B') {
return algorithmB(salary*3);
}
if (level === 'C') {
return algorithmC(salary*2);
}
}
这么修改之后,这些算法我们可以在其他函数里面复用了,但是还是没有解决calculateBonus函数庞大的问题。
3、使用策略模式重构代码
一个策略模式的程序至少由两部分组成
- 一组策略类,也就是算法,这些策略类会封装算法,并且负责具体的计算规则
- 环境上下文,接受客户的请求,然后把请求委托给某一个策略类。因此在这个上下文中要维持对某一个策略对象的引用。
我们先看一个模仿面向对象语言的实现:
// 策略类
var algorithmA = function(){}
algorithmA.prototype.calculate = function(salary) {
return salary*4;
}
var algorithmB = function(){}
algorithmB.prototype.calculate = function(salary) {
return salary*3;
}
var algorithmB = function(){}
algorithmB.prototype.calculate = function(salary) {
return salary*2;
}
// 环境上下文
var Bonus = function(){
this.salary = null;
this.strategy = null;
}
Bonus.prototype.setSalary = function(salary) {
this.salary = salary;
}
Bonus.prototype.setStrategy = function(strategy) {
this.strategy = strategy;
}
Bonus.prototype.getBonus = function() {
return this.strategy.calculate( this.salary );
}
// 使用
var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new algorithmA());
console.log(bonus.getBonus());
刚才上面说到了面向对象的的实现,但是其实我们很少会这样写,我们看看JavaScript的版本
4、JavaScript版本的策略模式
var strategies = {
"A": function(salary) {
return salary*4;
},
"B": function(salary) {
return salary*3;
},
"C": function(salary) {
return salary*2;
},
};
var calculateBonus = function(level, salary) {
return strategies[level](salary);
};
calculateBonus('A', 10000);
惊不惊喜,意不意外,就是这么简单。
策略模式更加广义的用法
上面我们说的策略模式封装的是算法,但是实际上我们不仅仅可以封装算法,还可以封装一些业务规则,例如表单验证里面,我们可以封装不同的校验逻辑,这里就不举例说明了,如果有兴趣可以参考JavaScript设计模式与实践这本书
策略模式的优缺点
优点:
- 策略模式利用组合、委托和多态的技术和思想,能够有效的避免多重条件选择语句
- 策略模式符合开发-封闭原则,把算法封装在独立的strategy中,让算法利于切换、理解和扩展
- 策略模式的算法能够很方便的在其他地方复用
- 策略模式利用组合和委托让环境上下文有执行算法的能力,这也是继承的一种体现
缺点:
- 策略模式需要在代码中增加许多策略类或者策略对象
- 要使用好策略模式的前提是:必须了解所有的strategy,并且知道他们之间的不同点,这是违反最少知识原则的。
网友评论