@Dreamingboy
2018-04-22T11:30:55.000000Z
字数 2483
阅读 698
设计模式
策略模式是指定义一系列的算法,把这些算法一个个封装起来,并且使它们可以相互替换
假设现在有三个等级,每个等级的计算方式是不一样的,这样的话就会有三种计算奖金的方法,所以一般的话会有下面这样的奖金的计算方式:
function award(level, salary) {if (level === 'S') {return salary * 4;}if (level === 'A') {return salary * 3;}if (level === 'B') {return salary * 2;}}
但是,可以看到上面这种写法有下面几个问题:
针对上面的这几个问题,得到基本的解决问题的思路:
具体代码如下:
//函数柯里化function strategy(number) {return function (salary) {return number * salary;};}//构造出一个独享存放计算方法const strategies = {S: strategy(4),A: strategy(3),B: strategy(2),};const calculate = function (level, salary) {return strategies[level](salary);};console.log(calculate('S', 1000));console.log(calculate('A', 1000));
看过上面的例子,再来看看策略模式的相关理论知识
一个基本的策略模式包括两个部分:
结合上面的例子,可以看到strategies就是策略类,里面封装了具体的算法,而calculate是环境类,将请求委托给了某一个策略类。
// 策略类class Performance {constructor() {}// 等级S计算方法performanceS(salary) {return salary * 4;}// 等级A计算方法performanceA(salary) {return salary * 3;}// 等级B计算方法performanceB(salary) {return salary * 2;}}// 环境类class Bonus {constructor() {this.salary = null; // 原始工资this.strategy = null; // 绩效等级对应的策略对象}// 设置员工的初始工资setSalary(salary) {this.salary = salary;}// 设置员工绩效等级对应的策略setStrategy(strategy) {this.strategy = strategy;}// 获取奖金getBonus() {console.log(this.strategy(this.salary));}}// 创建一个策略类的实例const performance = new Performance();// 创建一个环境类const bonus = new Bonus();// 计算奖金bonus.setSalary(1000);bonus.setStrategy(performance.performanceS);bonus.getBonus();
从上面的例子可以很好的看到策略模式中策略类和环境了之间的分离已经各自担任的任务。但是和使用对象的方式进行对比可以看到模仿传统的面向对象的实现方法相对来说比较麻烦,代码量增加了很多,利用JavaScript本身的对象和闭包实现的函数工厂可以很好的避免上面的问题。
上面的几个例子在进行奖金的计算的时候都是明确传入了奖金的计算等级的,但是现实中很多时候都是没有办法事先知道奖金的计算级别的,比如现在奖金的计算规则改成根据每个月的绩效进行级别的划分然后再进行奖金的计算,如下例子:
function award(salary) {if (10000 < salary < 20000) {return salary * 0.2;}if (20000 < salary < 30000) {return salary * 0.3;}if (30000 < salary < 40000) {return salary * 0.4;}}
上面这个例子如果使用策略模式来进行改写,需要如何改写呢?直接代码:
const sections = {section1: [10000, 20000, 0.2],section2: [20000, 30000, 0.3],section3: [30000, 40000, 0.4],};function strategy(condition) {return function (salary) {for (const key in condition) {if (condition[key][0] < salary && condition[key][1] > salary) {console.log(salary * condition[key][2]);}}};}const calculate = function (salary) {strategy(sections)(salary);};calculate(15000);
关键就在于将判断的公共部分抽取出来,因为逻辑具有很多的相似性,所以将逻辑写在工厂函数中,而section相当于是一个策略组,里面包含了各个区间的判断的条件。