转载

JavaScript策略模式学习与实践

策略模式

策略模式 的定义: 定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换

举个形象的例子,使用策略模式 计算奖金

业务需求:

  • 绩效为 S 的人年终奖有 4倍 工资

  • 绩效为 A 的人年终奖有 3倍 工资

  • 绩效为 B 的人年终奖有 2倍 工资

财务部希望我们可以提供一段代码,方便他们计算员工的年终奖。

最初的代码实现

我们可以编写一个名为 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

可以发现,这段代码非常简单,但是存在着显而易见的缺点。

  1. calculateBonus 函数比较庞大,包含了很多if语句,这些语句需要覆盖所有的 逻辑分支

  2. calculateBonus 函数缺乏 弹性 ,如果增加新的绩效等级,那我们必须深入 calculateBonus 内部,违反了 开放-封闭 原则

  3. 算法的 复用性 差,如果在程序的其他地方需要重用这些计算奖金的算法,我们的选择只有复制和粘贴

因此,我们要 重构 这段代码。

使用组合函数重构代码

我们把各种算法封装到一个个 小函数 里面:

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版本的策略模式

上述代码是模拟了一些传统的面向对象语言的实现,实际上在 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语言中, 策略类 往往被函数所替代,这是策略模式就成为了一种 隐形 的模式。尽管这样,彻底了解策略模式,也有助于我们明白使用函数的好处。

原文  https://segmentfault.com/a/1190000004574435
正文到此结束
Loading...