Javascript设计模式之策略模式

223 阅读2分钟

定义

定义一系列的算法,把它们一个个封装起来,并可以随意的相互替换。 策略模式的目的就是将算法的使用与算法的实现分离开来(将各种算法的代码、 内部数据和依赖关系与其他代码隔离开来)。

优缺点

优点:

  • 优化一些多重条件的逻辑判断代码
  • 开放封闭原则,易于切换算法,易于扩展
  • 将不同行为抽取到一个独立类层次结构中,并将原始类组合成同一个,从而减少重复代码,易于复用

缺点:

  • 程序中会有较多策略类

适用范围

  • 需要了解算法的不同点,才可以编写合适的策略类(即算法规则)
  • 算法的使用与算法的实现分离开,也就是说,算法的上下文逻辑不是特别重要,这样才有分离的意义

策略模式的组成

一个策略模式至少由两部分组成。

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

示例一:优化表单校验代码

需求背景

假设一个表单提交时,需要验证一下信息:

  • 用户名不能为空
  • 密码长度不能少于6位
  • 手机号码必须符合格式

常规写法

const form = document.getElementById('registerForm');
form.onsubmit = function () {
  if (form.userName.value === '') {
    alert('用户名不能为空');
    return false;
  }
  if (form.password.value.length < 6) {
    alert('密码长度不能少于6位');
    return false;
  }
  if (!/^1[3|5|8][0-9]{9}$/.test(form.phoneNumber.value)) {
    alert('手机号码格式不正确');
    return false;
  }
}

缺点:

  • if-else语句太多,onsubmit函数庞大
  • 违反开放-封闭原则:需要新增一个校验规则时,需要修改onsubmit函数内部

使用策略模式

// step1:编写策略类
const strategies = {
  isNonEmptyfunction (value, errMsg) {
    if (value === '') {
      return errMsg;
    }
  },
  minLenthfunction (value, length, errMsg) {
    if (value.length < length) {
      return errMsg;
    }
  },
  isMobilefunction (value, errMsg) {
    if (!/^1[3|5|8][0-9]{9}$/.test(value)) {
      return errMsg;
    }
  }
}

// step2:定义环境类 Context
class Validator {
 constructor() {
  this.cache = [];
 }

 add(dom, rule, errMsg) {
  const arr = rule.split(':');
  this.cache.push(() => {
   const strategy = arr.shift();
   arr.unshift(dom.value);
   arr.push(errMsg);
   return strategies[strategy].apply(dom, arr);
  })
 }

 start() {
  for (let i = 0; i < this.cache.length; i++) {
   const msg = this.cache[i]();
   if (msg) return msg;
  }
 }
}

// step3:调用策略
form.onsubmit = function () {
 const validator = new Validator();
 validator.add(form.userName'isNonEmpty''用户名不能为空');
 validator.add(form.password'minLength:6''密码长度不能少于6位');
 validator.add(form.phoneNumber'isMobile''手机号码格式不正确');
 const errMsg = validator.start();
 if (errMsg) {
  alert(errMsg);
  return false;
 }
}

示例二:减少if-else

只会if-else和switch?多层逻辑判断的优雅写法