设计模式之策略模式
策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
策略模式主要用来解决当有多种相似算法的时,使用if…else产生的难以维护的问题。它主要由三部分组成:strategy接口、具体的strategy类以及用来改变和执行策略的context类。其中,Context接受客户的请求,随后
把请求委托给某一个策略类。
使用策略模式计算奖金
很多公司的年终奖是根据员工的工资基数和年底绩效情况来发放的。例如,绩效为 S 的人年
终奖有 4 倍工资,绩效为 A 的人年终奖有 3 倍工资,而绩效为 B 的人年终奖是 2 倍工资。假设财
务部要求我们提供一段代码,来方便他们计算员工的年终奖。
不使用策略模式实现年终奖计算:
1 2 3 4 5 6 7 8 9 10 11 12 13
| let 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 ); calculateBonus( 'S', 6000 );
|
这段代码十分简单,但存在着显而易见的缺点。if-else分支太多,calculateBonus 函数缺乏弹性,如果增加了一种新的绩效等级 C,又要重写一个判断,代码冗余。
使用策略模式重构代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
| interface IStrategy{ calculate(salary:number):number }
class PerformanceS implements IStrategy { calculate (salary:number) { return salary * 4 } }
class PerformanceA implements IStrategy { calculate (salary:number) { return salary * 3 } }
class PerformanceB implements IStrategy { calculate (salary:number) { return salary * 2 } }
class Bonus { salary:number=0 strategy:any = null
setSalary (salary:number){ this.salary = salary }
setStrategy (strategy:strategyType){ this.strategy = strategy }
getBonus(){ return (this.strategy as strategyType).calculate(this.salary) } }
let bonus = new Bonus() bonus.setSalary(10000); bonus.setStrategy(new PerformanceS()) console.log(bonus.getBonus())
bonus.setStrategy(new PerformanceA()) console.log(bonus.getBonus())
|
可以看到通过策略模式重构之后,代码变得更加清晰,各个类的职责更加鲜明。
使用策略模式实现超市选择优惠活动
在超市里购物时,通常存在两种优惠,一是满减优惠,二是某某商品打折扣。
使用策略模式实现通过其中一种优惠计算最终需要支付的金额
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| interface strategy { discount(money: number): number }
class FullandReduceStrategy implements strategy { private conditionMoney: number; private reduceMoney: number;
constructor(money:number, returnMoney:number){ this.conditionMoney = money; this.reduceMoney = returnMoney }
public discount(money: number): number { let result: number = money; if(money >= this.conditionMoney){ result = money - Math.floor(money / this.conditionMoney) * this.reduceMoney } return result } }
class CashRebateStrategy implements strategy{ private moneyRebate:number;
constructor(moneyrabate:number){ this.moneyRebate = moneyrabate }
discount(money: number): number { return money * this.moneyRebate } }
class Context { private strategy:any = null private money:number
constructor(money:number){ this.money = money }
setStrategy(strategy:strategy){ this.strategy = strategy }
execute(){ return (this.strategy as strategy).discount(this.money) } }
const context:Context = new Context(50) context.setStrategy(new FullandReduceStrategy(50,2)) console.log(context.execute())
context.setStrategy(new CashRebateStrategy(0.5)) console.log(context.execute())
|
通过使用策略模式,我们消除了原程序中大片的条件分支语句。所有跟计算有关的逻辑不再放在 Context 中,而是分布在各个策略对象中。Context 并没有计算的能力,而是把这个职责委托给了某个策略对象。每个策略对象负责的算法已被各自封装在对象内部。当我们对这些策略对象发出“计算”的请求时,它们会返回各自不同的计算结果,这也是对象多态性的体现。