定义:
定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
实现策略模式
策略模式不好直接用代码来说,而是先举一些例子。
比如去旅游选择交通工具:
上面的几种方式都可以把你带到目的地,根据个人实际需求可以相互替换。
还有根据绩效算年终奖:
根据不同的评分等级,计算不同的年终奖。
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
}
}
这段代码:
- 既有判断等级的逻辑又有计算奖金的逻辑,违反了单一职责;
- 若哪天需要加另一个等级 D 需要直接在函数里面修改,违反了开闭原则;
- 如果需要在别的地方使用其中一个等级,只能 C / V 大法,没有复用性。
重新更改上面代码:
- 拆分
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
}