Skip to content

Instantly share code, notes, and snippets.

@simonwoo
Last active November 21, 2016 21:52
Show Gist options
  • Save simonwoo/59c35048810d7829568047fa35ba3cd6 to your computer and use it in GitHub Desktop.
Save simonwoo/59c35048810d7829568047fa35ba3cd6 to your computer and use it in GitHub Desktop.

定义

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

例子

问题描述:年终奖是根据员工的基本工资和年底绩效来计算的。规则如下:

  • 绩效S -> 4*salary
  • 绩效A -> 3*salary
  • 绩效B -> 2*salary

面向过程代码如下:

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

这段代码有多个if-else,如果后期增加新的工资计算方式时,难以扩展。为了解决这个问题,我们引入策略模式,将算法的使用过和算法的实现分离开来。 一个基于策略模式的程序至少有两部分组成:第一部分是策略类,策略类封装了具体的算法,并负责具体的计算过程。 第二个部分是环境类Context, Context接受客户的请求,随后把请求委托给某一个策略类。

传统的策略模式实现如下:

// Strategy: 一系列算法,可相互替换(实现相同的接口)
var performanceS = function () {};
performanceS.prototype.calculate = function(salary) {
  return salary * 4;
}

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

var performanceB = function () {};
performanceB.prototype.calculate = function(salary) {
  return salary * 2;
}

// Context: 客户端,委托具体的策略
var Bonus = function (salary, strategy) {
  this.salary = salary;
  this.strategy = strategy;
};

Bonnus.prototype.getBonus = function () {
  return  this.stategy.calculate(this.salary);
};

Javascript版本的实现:

var strategies = function () {
  "S" : function(salary) {
    return salary * 4;
  },
  "A" : function(salary) {
    return salary * 3;
  },
  "B" : function(salary) {
    return salary * 2;
  }
};

var getBonus = function(salary, strategy) {
  return strategies[strategy](salary);
};

通过策略模式,我们消除了程序中大片的if-else语句,所有跟计算相关的逻辑都不放在Context中,而是分布在各个策略中。 Context并没有计算奖金的能力,而是把这个职责委托给具体的策略类。每个策略类负责的算法被封装在各自的类中,负责完成具体的计算过程。 通过替换Context中具体的策略对象,我们便能执行不同的算法。

Web开发中的事例

  • 使用不同的策略实现动画(TODO)
  • 表单验证(使用策略模式封装一系列业务规则,这些业务规则指向同一个目标,可以被替换)(TODO)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment