策略模式

定义

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

详细描述

传统意义的策略模式如上所述,定义策略类封装一系列的算法,然后根据场景使用对应的算法。在js语言中对象、函数都可以不使用类来封装生成,直接进行定义即可,这就使策略模式在js中更加的灵活简单,并且根据实际业务从广义上来说算法,不单单只是计算的规则成为算法,还可以是一系列的业务规则根据不同场景替换展示不通的业务规则,我们就可以说它是策略模式。

实例

首先来看一下在js中不使用策略模式来计算两个数之间进行加减乘除等运算的例子:

const calculation = (type, num1, num2) => {
    if (type === 'add') {
      return num1 + num2;
    }

    if (type === 'subtraction') {
      return num1 - num2;
    }

    if (type === 'multiplication') {
      return num1 * num2;
    }

    if (type === 'division') {
      return num1 / num2;
    }
  }

  console.log(calculation('add', 2, 2)); // 4

  console.log(calculation('division', 4, 2)); // 2

上述代码是一个根据传入的type,来计算两个数值的结果,如果是加就返回num1+num2的和,减法就返回num1 – num2的差。假如此时我还想添加其他的计算规则就需要写更多的if语句来实现,最后会使我的calculation 函数越来越臃肿不易于维护,如果此时我另外的业务中也使用到了相同的代码,那我只能拷贝一份在那里面使用,也不利于代码的复用。下面我们使用策略模式思想来重构我们的代码。

// 定义策略对象-包含可以根据场景进行替换的算法或者业务规则
  const calculationObj = {
    add(num1, num2) {
      return num1 + num2;
    },

    subtraction(num1, num2) {
      return num1 - num2;
    },

    multiplication(num1, num2) {
      return num1 * num2;
    },

    division(num1, num2) {
      return num1 / num2;
    }
  };

  // 委托策略对象进行计算
  const calculation = (type, num1, num2) => {
    return calculationObj[type](num1, num2);
  }

  console.log(calculation('add', 2, 2)); // 4

  console.log(calculation('division', 4, 2)); // 2

  console.log(calculation('multiplication', 4, 2)); // 8

上述代码使用策略模式思想重写了原来的逻辑,首先定义一个集合了所有算法的策略对象calculationObj,然后根据传入的type对策略对象的算法进行调用,如果我想要在增加一个算法只需要在策略对象calculationObj中增加一个算法即可实现,因为调用算法的方法总是不变的,只需要根据业务场景调用策略对象calculationObj不同的算法。

总结

在js中因为js语言本身的特点(函数也是对象,所有的对象都不需要使用类创建)使用策略模式不需要使用类来创建,这就使我们可以直接将策略对象和算法规则直接定义,调用时使用函数方法直接调用即可,大大简化了我们的代码和使用规则。
除了使用上更简单外,策略模式还有以下优点:

  • 策略模式利用组合、委托等技术和思想,可以有效地避免多重条件选择语句。
  • 抽离出策略对象后将不变的和可变的分开后,更加易于理解和扩展(只需要在策略对象添加新的规则即可)。
  • 可以将策略对象当做模块暴露出去,里面的算法规则在不通的模块不同的页面都可以轻易的进行复用,而且避免代码冗余。