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

策略模式的定义看起来可能比较抽奖,下面我们用一个例子来解释它。

计算奖金

小明公司的年终奖会根据员工的工资基础和年底绩效来进行发放,如:绩效为 S 的人年终奖为 4 倍工资,A 的人为 3 倍工资,B 的人为 2 倍工资,如果让我们写代码来实现,该怎么实现呢?

不使用策略实现

  1. function calculateBonus(leave, salary) {
  2. if (leave === 'S') {
  3. return salary * 4;
  4. } else if (leave === 'A') {
  5. return salary * 3;
  6. } else if (leave === 'B') {
  7. return salary * 2;
  8. }
  9. }
  10. calculateBonus('S', 1000); // 4000
  11. calculateBonus('A', 1000); // 3000

上面这样写的代码是很简单的,但是它存在一些问题:

  1. 所有计算规则堆积到了一起,包含了很多 if else 语句。
  2. 如果我们想要新增其他规则的时候就需要深入 calculateBonus 函数,这违反了开发封闭原则。
  3. 代码复用性差,假如说其他地方遇到用到 SA 算法时我们需要赋值粘贴过去。

策略默认实现

一个基于策略模式的程序至少由两部分组成,第一部分是策略类,用于封装具体的算法,第二部分是环境类 Context,用于接收用户的请求然后把请求委托给某个策略类。

现在我们来实现一下:

  1. // 策略类
  2. function LeaveS() {}
  3. LeaveS.prototype.calculate = (salary) => salary * 4;
  4. function LeaveA() {}
  5. LeaveA.prototype.calculate = (salary) => salary * 3;
  6. function LeaveB() {}
  7. LeaveB.prototype.calculate = (salary) => salary * 2;
  8. // Context 环境类
  9. function Bonus(leave, salary) {
  10. this.leave = leave;
  11. this.salary = salary;
  12. }
  13. Bonus.prototype.getBonus = function() {
  14. return this.leave.calculate(this.salary)
  15. };
  16. // 用户请求
  17. new Bonus(new LeaveS(), 3000).getBonus(); // 12000
  18. new Bonus(new LeaveA(), 3000).getBonus(); // 9000

当后面想要新增一个计算规则时,我们只需要创建一个对应的策略类就可以了,然后再用户请求时给 Bouns 传递对应的策略对象即可(互相替换),而且每个类的职责更明显了,复用性也变强了。

JavaScript 中的策略模式

上面的代码是基于传统的面向对象语言来实现的,在 JavaScript 中函数也是对象,且没有类型之间的限制,所以实现起来非常简单,我们只需要将策略类改为函数,然后把它们组合起来就好了。

  1. // 策略函数
  2. const strategies = {
  3. S: (salary) => salary * 4,
  4. A: (salary) => salary * 3,
  5. B: (salary) => salary * 2,
  6. };
  7. // Context
  8. const getBouns = (leave, salary) => {
  9. return strategies[leave](salary);
  10. };
  11. getBouns('S', 3000); // 12000
  12. getBouns('A', 3000); // 9000

更广义的策略模式

先来看一下策略模式的定义:

定义一系列算法,把它们一个个封装起来,并且使它们可以互相替换。

从定义上来看策略模式是用来定义算法的,但如果只用策略模式来定义算法就会显得有点大材小用,在实际开发中我们也可以用用来封装一些 “业务逻辑”,将臃肿的 if else 代码拆分出来。

整理与 JavaScript 设计模式与开发实践。