Javascript之策略模式

237 阅读3分钟

定义

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

越狱相信大部分都看过,第一部剧中迈克尔设计了两条通往医务室的道路。国庆节、春节回家的方式很多种,我们可以选择飞机、高铁,还可以坐火车、大巴车。

作用

策略模式最主要的作用是在我们想找一种方式替换太多if else的条件语句,因为条件语句会让程序难以维护,且违反开放-封闭原则。

举例

根据模式的作用,我们来举例:

var calculateBonus = function (performanceLevel, salary) {
    if (performanceLevel === 'S') {
        return salary * 4;
    }
    if (performanceLevel === 'A') {
        return salary * 3;
    }
    if (performanceLevel === 'B') {
        return salary * 2;
    }
};

// test
calculateBonus('B', 20000);    // 40000
calculateBonus('A', 6000);    // 18000

上面的代码就是我们一开始说的,太多if else条件判断语句,且我们想增加第四种模式,比如'C'时,我们需要修改代码内部,添加如下代码:

if (performanceLevel === 'C') {
    return salary;
}

最后这个calculateBonus会多么庞大,想想就恶心。下面我们使用策略模式来重构一下代码,模式的目的就是讲算法的使用与算法的实现分离开来。

一个策略模式的程序至少由两部分组成。第一部分是一组策略类策略类封装了具体的算法,并负责具体的计算过程。第二个部分是环境类context,Context接受客户的请求。随后把请求委托给某一个策略类。

var performanceS = function () {};

performanceS.prototype.calculate = function (salary) {
    return salary * 4;
};

var performanceA = function () {};

performanceS.prototype.calculate = function (salary) {
    return salary * 3;
};

var performanceB = function () {};

performanceS.prototype.calculate = function (salary) {
    return salary * 2;
};
var Bonus = function () {
    this.salary = null;    // 原始工资
    this.strategy = null;    // 绩效等级对应的策略对象
};

Bonus.prototype.setSalary = function (salary) {
    this.salary = salary;    // 设置员工的原始工资
};

Bonus.prototype.setStrategy = function (salary) {
    this.strategy  = strategy ;    // 设置员工绩效等级对应的策略对象
};

Bonus.prototype.getBonus = function () {    // 取得奖金数额
    return this.strategy.calculate(this.salary);    // 把计算奖金的操作委托给对应的策略对象
};

测试代码:

var bonus = new Bonus();

bonus.setSalary(10000);
bonus.setStrategy(new PerformanceS());

console.log(bonus.getBonus());    // 40000

bonus.setStrategy(new PerformanceA());
console.log(bonus.getBonus());    // 30000

上面的重构代码利用传统的OOP,在JS中,这个重构方式显得太笨拙了。函数也是对象,我们更直接和简洁的做法是把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', 20000));    // 80000
console.log(calculateBonus('A', 10000));    // 30000

策略模式在前端开发中更常见的使用时封装表单校验。

优点

  • 策略模式提供了对“开放-封闭原则”的完美支持,用户可以在不修改原有系统的基础上选择算法或行为,也可以灵活地增加新的算法或行为。
  • 策略模式提供了管理相关的算法族的办法。
  • 策略模式提供了可以替换继承关系的办法。
  • 使用策略模式可以避免使用多重条件转移语句。

缺点

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
  • 策略模式将造成产生很多策略类,可以通过使用享元模式在一定程度上减少对象的数量。

小结

本文通过提供接近传统面向对象语言的策略模式,也提供了更适合Javascript语言的策略模式版本。在Javascript语言的策略模式中,策略类往往被函数所替代,这时策略模式就成为一种“隐形”的模式。

系列文章关注博客