全部 / 前端 / 技术 · 2022年5月16日 0

策略模式

2022-05-16+11_54_58

定义:

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

实现策略模式

策略模式不好直接用代码来说,而是先举一些例子。

比如去旅游选择交通工具:

上面的几种方式都可以把你带到目的地,根据个人实际需求可以相互替换。

还有根据绩效算年终奖:

根据不同的评分等级,计算不同的年终奖。

function getBonus(level, salary) {
  if (level === 'S') {
    return salary * 4
  } else if (level === 'A') {
    return salary * 3
  } else if (level === 'B') {
    return salary * 2
  } else if (level === 'C') {
    return salary * 1
  }
}

这段代码:

  1. 既有判断等级的逻辑又有计算奖金的逻辑,违反了单一职责;
  2. 若哪天需要加另一个等级 D 需要直接在函数里面修改,违反了开闭原则;
  3. 如果需要在别的地方使用其中一个等级,只能 C / V 大法,没有复用性。

重新更改上面代码:

  1. 拆分
function sLevel(salary) {
  return salary * 4
}

function aLevel(salary) {
  return salary * 3
}

function bLevel(salary) {
  return salary * 2
}

function cLevel(salary) {
  return salary * 1
}

function getBonus(level, salary) {
  if (level === 'S') {
    return sLevel(salary)
  } else if (level === 'A') {
    return aLevel(salary)
  } else if (level === 'B') {
    return bLevel(salary)
  } else if (level === 'C') {
    return cLevel(salary)
  }
}

getBonus('S',1000)

经过拆分,计算逻辑被拆出去了,同时达到了复用性。但是现在还有问题,若此时再加一个等级,还是需要在 getBonus 函数里修改,还是没有解决开闭原则的问题,同时也会造成该函数越来越臃肿。只是单一职责的原则得到了稍微改善。

我们要始终记住设计模式的主题:将不变的部分和变化的部分隔开,这里变化的部分是计算奖金的逻辑,不变的是根据等级调用不同的计算逻辑,getBonus 里主要是完成了:等级-计算奖金函数的映射,那 JavaScript 中对象具有映射能力:


let strategies = {
  'S': function (salary) {
    return salary * 4
  },
  'A': function (salary) {
    return salary * 3
  },
  'B': function (salary) {
    return salary * 2
  },
  'C': function (salary) {
    return salary * 1
  }
}


function getBonus(level, salary) {
  return strategies[level](salary)
}

getBonus('S',1000)

此时再需要加等级 D 也不会到 getBonus 中修改,所以也不会增加那里的代码逻辑,真是实现了单一职责。

strategies.D = function (salary) {
  return salary * 0.9
}