策略模式
看本文之前需要有JavaScript的基础知识
策略模式的定义是:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。
一、使用策略模式计算奖金
最初代码实现:
var calculateBonus = function(performanceLevel, salary){
if(performanceLevel === 'S'){
return salary * 4;
}
if(performanceLevel === 'A'){
return salary * 3;
}
if(performanceLevel === 'B'){
return salary * 2;
}
};
calculateBonus('B',20000); // 40000
calculateBonus('S',6000); // 24000这段代码十分简单,但是存在着显而易见的缺点:
calculateBonus
函数比较庞大,包含了很多if-else语句,这些语句需要覆盖所有的逻辑分支。calculateBonus
函数缺乏弹性违反开放-封闭原则算法的复用性差
使用组合函数重构代码
var performanceS = function(salary){
return salary * 4;
};
var performanceA = function(salary){
return salary * 3;
};
var performanceB = function(salary){
return salary * 2;
};
var calculateBonus = function(performanceLevel, salary){
if(performanceLevel === 'S'){
return performanceS(salary);
}
if(performanceLevel === 'A'){
return performanceA(salary);
}
if(performanceLevel === 'B'){
return performanceB(salary);
}
};
calculateBonus('A',10000); // 30000使用策略模式重构代码
策略模式指的是定义一系列的算法,把它们一个个封装起来。将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式的目的就是将算法的使用与算法的实现分离开来。
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给某一个策略类。
也可以有三种:抽象策略(strategy)类、具体策略(Concrete Strategy)类、环境(Context)类。
var performanceS = function(){};
performanceS.prototype.calculate = function(salary){
return salary * 4;
};
var performanceA = function(){};
performanceA.prototype.calculate = function(salary){
return salary * 3;
};
var performanceB = function(){};
performanceB.prototype.calculate = function(salary){
return salary * 2;
};
// 接下来定义奖金类Bonus
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.prorotype.getBonus = function(){ // 取得奖金数额
if(!this.strategy){
throw new Error('未设置strategy属性');
}
return this.strategy.calculate(this.salary); // 把计算奖金操作委托给对应的策略对象
};
var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new performanceS()); // 设置策略对象
console.log(bonus.getBonus()); // 40000
bonus.setStrategy(new performanceA()); // 设置策略对象
console.log(bonus.getBonus()); // 30000
二、JavaScript版本的策略模式
实际上在JavaScript语言中,函数也是对象,所以更简单和直接的做法是把strategy直接定义为函数:
将判断语句改写成对象形式可以消除大片的条件分支语句
var strategies = { |
三、多态在策略模式中的体现
通过使用策略模式重构代码,我们消除了原程序中大片的条件分支语句。所有跟计算奖金有关的逻辑不再放在Context中,而是分布在各个策略对象中。Context并没有计算奖金的能力,而是把这个职责委托给了某个策略对象。每个策略对象负责的算法已被各自封装在对象内部。当我们对这些策略对象发出”计算奖金”的请求时,它们会返回各自不同的计算结果,这正是对象多态性的体现,也是”它们可以相互替换”的目的。替换Context中当前保存的策略对象,便能执行不同的算法来得到我们想要的结果。
四、策略模式的优缺点
优点:
- 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。
- 策略模式提供了对开放-封闭原则地完美支持,将算法封装在独立的strategy中,使得它们易于切换,易于理解,易于扩展。
- 策略模式的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
- 在策略模式中利用组合和委托来让Context拥有执行算法的能力,这也是继承的一种更轻便的代替方案。
缺点:
使用策略模式会在程序中增加许多策略类或者策略对象,但实际上这比把它们负责的逻辑堆砌在Context中要好。
要使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同点,这样才能选择一个合适的strategy。
五、小结
在JavaScript语言的策略模式中,策略类往往被函数所代替,这时策略模式就成为一种”隐式”的模式。