[关闭]
@Dreamingboy 2018-04-22T11:30:55.000000Z 字数 2483 阅读 698

策略模式

设计模式


1 定义

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

2 策略模式实现奖金计算

2.1 没有使用策略模式

假设现在有三个等级,每个等级的计算方式是不一样的,这样的话就会有三种计算奖金的方法,所以一般的话会有下面这样的奖金的计算方式:

  1. function award(level, salary) {
  2. if (level === 'S') {
  3. return salary * 4;
  4. }
  5. if (level === 'A') {
  6. return salary * 3;
  7. }
  8. if (level === 'B') {
  9. return salary * 2;
  10. }
  11. }

但是,可以看到上面这种写法有下面几个问题:

2.2 使用策略模式改写

针对上面的这几个问题,得到基本的解决问题的思路:

具体代码如下:

  1. //函数柯里化
  2. function strategy(number) {
  3. return function (salary) {
  4. return number * salary;
  5. };
  6. }
  7. //构造出一个独享存放计算方法
  8. const strategies = {
  9. S: strategy(4),
  10. A: strategy(3),
  11. B: strategy(2),
  12. };
  13. const calculate = function (level, salary) {
  14. return strategies[level](salary);
  15. };
  16. console.log(calculate('S', 1000));
  17. console.log(calculate('A', 1000));

3 策略模式

看过上面的例子,再来看看策略模式的相关理论知识
一个基本的策略模式包括两个部分:

结合上面的例子,可以看到strategies就是策略类,里面封装了具体的算法,而calculate是环境类,将请求委托给了某一个策略类。

3.1 传统的面向对象语言实现策略模式

  1. // 策略类
  2. class Performance {
  3. constructor() {}
  4. // 等级S计算方法
  5. performanceS(salary) {
  6. return salary * 4;
  7. }
  8. // 等级A计算方法
  9. performanceA(salary) {
  10. return salary * 3;
  11. }
  12. // 等级B计算方法
  13. performanceB(salary) {
  14. return salary * 2;
  15. }
  16. }
  17. // 环境类
  18. class Bonus {
  19. constructor() {
  20. this.salary = null; // 原始工资
  21. this.strategy = null; // 绩效等级对应的策略对象
  22. }
  23. // 设置员工的初始工资
  24. setSalary(salary) {
  25. this.salary = salary;
  26. }
  27. // 设置员工绩效等级对应的策略
  28. setStrategy(strategy) {
  29. this.strategy = strategy;
  30. }
  31. // 获取奖金
  32. getBonus() {
  33. console.log(this.strategy(this.salary));
  34. }
  35. }
  36. // 创建一个策略类的实例
  37. const performance = new Performance();
  38. // 创建一个环境类
  39. const bonus = new Bonus();
  40. // 计算奖金
  41. bonus.setSalary(1000);
  42. bonus.setStrategy(performance.performanceS);
  43. bonus.getBonus();

从上面的例子可以很好的看到策略模式中策略类和环境了之间的分离已经各自担任的任务。但是和使用对象的方式进行对比可以看到模仿传统的面向对象的实现方法相对来说比较麻烦,代码量增加了很多,利用JavaScript本身的对象和闭包实现的函数工厂可以很好的避免上面的问题。

4 策略模式实现区间判断

上面的几个例子在进行奖金的计算的时候都是明确传入了奖金的计算等级的,但是现实中很多时候都是没有办法事先知道奖金的计算级别的,比如现在奖金的计算规则改成根据每个月的绩效进行级别的划分然后再进行奖金的计算,如下例子:

  1. function award(salary) {
  2. if (10000 < salary < 20000) {
  3. return salary * 0.2;
  4. }
  5. if (20000 < salary < 30000) {
  6. return salary * 0.3;
  7. }
  8. if (30000 < salary < 40000) {
  9. return salary * 0.4;
  10. }
  11. }

上面这个例子如果使用策略模式来进行改写,需要如何改写呢?直接代码:

  1. const sections = {
  2. section1: [10000, 20000, 0.2],
  3. section2: [20000, 30000, 0.3],
  4. section3: [30000, 40000, 0.4],
  5. };
  6. function strategy(condition) {
  7. return function (salary) {
  8. for (const key in condition) {
  9. if (condition[key][0] < salary && condition[key][1] > salary) {
  10. console.log(salary * condition[key][2]);
  11. }
  12. }
  13. };
  14. }
  15. const calculate = function (salary) {
  16. strategy(sections)(salary);
  17. };
  18. calculate(15000);

关键就在于将判断的公共部分抽取出来,因为逻辑具有很多的相似性,所以将逻辑写在工厂函数中,而section相当于是一个策略组,里面包含了各个区间的判断的条件。

添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注