策略模式

119 阅读3分钟

我们可以编写一个名为 calculateBonus 的函数来计算每个人的奖金数额。很显然,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

缺点:calculateBonus 函数比较庞大,包含了很多 if-else 语句,这些语句需要覆盖所有的逻辑分支。calculateBonus 函数缺乏弹性,如果增加了一种新的绩效等级 C,或者想把绩效 S 的奖金系数改为 5,那我们必须深入 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 函数有可能越来越庞大,而且在系统变化的时候缺乏弹性。

  • 使用策略模式重构代码

    1. 策略模式的思想:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。详细地说就是定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里

    2. 策略模式指的是定义: 一系列的算法,把它们一个个封装起来。将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。

    3. 一个基于策略模式的程序至少由两部分组成:第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类 Context,Context 接受客户的请求,随后把请求委托给某一个策略类。

var performanceS = function () {};
performanceS.prototype.calculate = function (salary) {
  return salary * 4;
};

var performanceA = function () {};
performanceA.prototype.calculate = function (salary) {
  return salary * 3;
};

var performanceB = function () {};
performanceB.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); // 把计算奖金的操作委托给对应的策略对象
};

var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new performanceS()); // 设置策略对象
console.log(bonus.getBonus()); // 输出:40000
bonus.setStrategy(new performanceA()); // 设置策略对象
console.log(bonus.getBonus()); // 输出:30000