定义:定义一系列算法,把他们一个个封装起来,并且使他们可以相互替换。
需求:绩效为S的人年终奖有4倍工资,绩效为A的人年终奖有3倍工资,绩效为B的人年终奖有2倍工资。
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函数比较庞大,包含了很多if语句,且缺乏弹性,如果增加新的绩效等级,复用性差,如果在程序的其他地方需要重用这些计算奖金的算法,我们的选择只有复制和粘贴。因此,我们要重构这段代码。
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函数可能越来越庞大,依旧缺乏弹性。
策略模式
这时候策略模式该出场了。
我们要将算法的使用与算法的实现分离开来
//我们先把每种绩效的计算规则封装在对应的策略类里
var porformanceS = function() {};
porformanceS.prototype.calculate = function(salary) {
return salary * 4;
};
var porformanceA = function() {};
porformanceA.prototype.calculate = function(salary) {
return salary * 3;
};
var porformanceB = function() {};
porformanceB.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(1000);
bonus.setStrategy(new performanceS());
bonus.getBonus();
JavaScript版本
在JavaScript中,函数即对象,因此我们可以直接把strategy定义成函数:
var strategies = {
“S”: function ( salary ){
return salary * 4;
},
“A”: function ( salary ){
return salary * 3;
},
“B”: function ( salary ){
return salary * 2;
}
};
var calculateBonus = function(level,salary){
return strategies[level](salary);
};
console.log(calculateBonus('S', 2000); //80000
console.log(calculateBonus('A', 1000); //30000