Fork me on GitHub

策略模式

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

需求:绩效为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
我知道是不会有人点的,但万一有人想不开呢?