策略模式的定义:定义一系列的算法,把它们一个个封装起来,并且使他们可以相互替换。
我们编写一个函数来计算每个人的奖金数额,这个函数接收两个参数:员工的工资数额和他的绩效考核等级
const calulateBous = (performanceLevel, salary) => { switch(performanceLevel) { case 'S': return salary*4 case 'A': return salary*3 case 'B': return salary*2 } }
我们可以看到上面那段代码有几个缺点:
case
语句,这些语句需要覆盖所有的逻辑分支 calulateBous
函数缺乏弹性,如果需要增加一个新的绩效等级 C,那我们必须深入 calulateBous
函数内部去实现,这是违反 开放-封闭原则
的 因此,我们需要重构这段代码
const performanceS = (salary) => { return salary*4 } const performanceA = (salary) => { return salary*3 } const performanceB = (salary) => { return salary*2 } const calulateBous = (performanceLevel, salary) => { switch(performanceLevel) { case 'S': return performanceS(salary) case 'A': return performanceA(salary) case 'B': return performanceB(salary) } }
目前,我们的程序得到了一点的改善,但是这种改善非常有限,我们依然没有解决最重要的问题: calulateBous
函数有可能越来越庞大,并且在系统变化时缺乏弹性。
const performanceS = function(){} performanceS.prototype.calulate = salary => { return salary*4 } const performanceA = function(){} performanceA.prototype.calulate = salary => { return salary*3 } const performanceB = function(){} performanceB.prototype.calulate = salary => { return salary*3 } const Bonus = function(){ this.salary = null // 原始工资 this.strategy = null // 绩效等级对应的策略对象 } Bonus.prototype.setSalary = salary => { this.salary = salary } Bonus.prototype.setStrategy = strategy => { this.strategy = strategy } Bonus.prototype.getBonus = () => { return this.strategy.calulate(this.salary) }
在 JavaScript 中,函数也是对象,所以更简单和直接的方法就是将 strategy 直接定义为对象。
const strategies = { S(salary) { return salary*4 }, A(salary) { return salary*3 } B(salary) { return salary*2 } }
同样的,Context 也没必要用 Bonus 来表示,我们依旧用 calculateBonus 来充当 Context 来接收用户的请求。
const calulateBous = (performanceLevel, salary) => { return strategies[performanceLevel](salary) }