策略模式:定义一系列的算法,并且一个个封装起来,使得他们可以相互替换(达成一个目的可以有多种不同的方法)。
设计模式的目的就是将算法中不变的部分和变的部分分隔开来。
1 传统面向对象的策略模式实现
策略模式的程序至少由两部分组成。第一部分是一组策略类,封装了具体的算法,负责具体实现。第二部分是环境类Context,Context接受客户请求,随后将请求委托给某个策略类。下面代码中的是书中的策略模式例子:计算年终奖,年终奖根据基本工资和绩效计算,绩效有S、A、B,对应4、3、2倍工资,计算员工年终奖。
- 1 先把每种绩效的计算规则封装到策略类里
let perfomanceS = function () {};
perfomanceS.prototype.calculate = function (salary) {
return salary * 4
};
let perfomanceA = function () {};
perfomanceA.prototype.calculate = function (salary) {
return salary * 3
};
let perfomanceB = function () {};
perfomanceB.prototype.calculate = function (salary) {
return salary * 2
}; - 2 环境类Context,定义奖金类
let 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 () { //取得奖金数额
if (!this.strategy) {
throw new Error('未设置strategy属性');
}
return this.strategy.calculate(this.salary); //把计算奖金的操作委托给对应的策略对象
} - 3 调用计算年终奖策略模式就是定义一系列的算法(perfomanceS、A、B),把他们各自封装成策略类,算法被封装在策略类的内部方法里。在用户对环境类Context发起请求时,Context总是把请求委托给这些策略对象中的某一个进行计算。上述是基于传统面向对象语言的策略模式。
let bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new perfomanceA()); //设置策略对象
console.log(bonus.getBonus());
2 javascript的的策略模式
- 1 前文中,我们模拟面向对象语言让策略对象从各个策略类中创建而来。在js中函数也是对象,可以直接把strategy定义为函数:
let strategies = {
'S': function (salary) {
return salary * 4
},
'A': function (salary) {
return salary * 3
},
'B': function (salary) {
return salary * 2
}
}; - 2 Context环境类也不一定要用Bonus类表示,用calculateBonus函数当作Context接受请求:
let calculateBonus = function (level, salary) {
return strategies[level](salary)
}; - 3 计算年终奖
console.log(calculateBonus('S', 20000));
3 策略模式总结
在计算年中奖金例子中,Context类对这些策略对象发出‘计算奖金’的请求的时候,他们会返回不同的计算结果,这就是对象多态性的体现。接下来文中还介绍了两个策略模式的例子:小球各种模式移动和表单验证。小球移动是动画类根据不同的移动策略类中的策略对象来进行移动;表单验证是验证类根据不同的效验模式的策略对象进行效验。
策略模式优点有利用组合、委托、多态等技术避免重复的判断语句;提供了对开放-封闭原则对完美支持,将算法封装在独立的策略类中;高复用性;组合和委托让Context有执行算法的能力也是继承的一种轻便方案。缺点有会增加许多策略类和策略对象;使用的时候必须了解strange类。
在js中策略类可以很方便的用函数替代,和OOP语言实现有较大区别。