本系列为《JavaScript设计模式与开发实践》(做者:曾探)学习总结,如想深刻了解,请支持做者原版javascript
策略模式
的定义:定义一系列的算法,把它们一个个封装起来,而且使它们能够互相替换。java
举个形象的例子,使用策略模式计算奖金
。算法
业务需求:设计模式
绩效为S
的人年终奖有4倍
工资函数
绩效为A
的人年终奖有3倍
工资学习
绩效为B
的人年终奖有2倍
工资this
财务部但愿咱们能够提供一段代码,方便他们计算员工的年终奖。prototype
咱们能够编写一个名为calculateBonus
的函数来计算员工的奖金数额,这个函数须要传入两个参数:工资数额
和绩效等级
。代码以下:设计
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
能够发现,这段代码很是简单,可是存在着显而易见的缺点。code
calculateBonus
函数比较庞大,包含了不少if语句,这些语句须要覆盖全部的逻辑分支
calculateBonus
函数缺少弹性
,若是增长新的绩效等级,那咱们必须深刻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
我們的程序获得了必定的改善,但我們依然沒有解決最重要的問題:calculateBonus
函數有可能越來越龐大,并且在系統變化的時候缺少彈性。
将不变的部分和变化的部分隔开是每一个设计模式的主题
,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来
。
一个基于策略模式的程序至少由两部分组成,第一部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二部分是环境类Context接受客户的请求,随后把请求委托给某一个策略类。
如今咱们用策略模式来重构上边的代码。
//咱们先把每种绩效的计算规则封装在对应的策略类里 var porformanceS = function() {}; porformanceS.prototype.calculate = function(salary) { return salary * 4; }; var porformanceA = function() {}; porformanceA.prototype.calculate = function(salary) { return salary * 3; }; var porformanceB = function() {}; porformanceB.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.prototype.getBonus = function() { return this.strategy.calculate(this.salary); }
在完成最終的代碼以前,我們再來回顧一下策略模式的思想
:
定義一系列的算法,把它們一個個封裝起來,並且使它們能够互相替換。
若是说的更详细一点,就是:定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对Context发起请求的时候,Context老是把请求委托给这些策略对象中的某一个进行计算。
咱们继续完成刚才的代码:
var Bonus = new Bonus(); bonus.setSalary(1000); bonus.setStrategy(new performanceS()); bonus.getBonus();
上述代码是模拟了一些传统的面向对象语言的实现,实际上在JavaScript
中,函数也是对象,因此更简单和直接的作法是把strategy
直接定义为函数:
var strategies = { "S": function ( salary ){ return salary * 4; }, "A": function ( salary ){ return salary * 3; }, "B": function ( salary ){ return salary * 2; } }; var calculateBonus=function(level,salary){ return strategies[level](salary); };
在JavaScript语言中,策略类
每每被函数所替代,这是策略模式就成为了一种隐形
的模式。尽管这样,完全了解策略模式,也有助于咱们明白使用函数的好处。