达到同一个目的可以用多种方法,在不同的情况下可以切换不同的方法达到同样的效果。策略模式关键在于将不同的算法处理过程封装起来,在不同情况下可以切换使用不同的算法,而不是直接将算法的实现逻辑写在不同分支语句内。
算法的实现和使用其实是两个职责,如果都写在if...else
结构语句内无疑违反了RSP
,同样违反了开闭原则。
这样做可以减少大量if...else/switch
语句,使代码更易维护、扩展。然而多了策略对象,在使用前得了解所有的策略,选择合适的策略。
封装算法的目的是解耦算法处理过程与调用者的关系,将算法的实现和使用区分开。分析大量if...else
语句,从两个职责来看,可以增加中间对象来解耦算法的实现和调用,转变为 3 个实体之间的关系(调用者、中间对象、实际的算法处理过程)。
传统面向对象语言将算法封装在类中,通过类将请求委托给具体的策略对象。而JavaScript
中可以使用对象和函数来封装算法。策略模式在JS
语言中是浑然天成的(主要体现在一等函数对象的函数式特性上,用高阶函数封装算法与行为,并且可以传递函数)。
// 计算奖金 - if...else
var calculateBonusIE = function(level, salary) {
if (level === "S") {
return salary * 4;
}
if (level === "A") {
return salary * 3;
}
if (level === "B") {
return salary * 2;
}
}
console.log(calculateBonusIE('S', 4000));
console.log(calculateBonusIE('A', 4000));
console.log('-------------------------');
// 计算奖金 - 策略模式版本
var strategies = {
"S": function (salary) {
return salary * 4;
},
"A": function (salary) {
return salary * 3;
},
"B": function (salary) {
return salary * 2;
}
}
function calculateBonus(level, salary) {
return strategies[level](salary);
}
console.log(calculateBonus('S', 4000));
console.log(calculateBonus('A', 4000));