定义
定义一系列的算法,把它们一个个封装起来,并可以随意的相互替换。 策略模式的目的就是将算法的使用与算法的实现分离开来(将各种算法的代码、 内部数据和依赖关系与其他代码隔离开来)。
优缺点
优点:
- 优化一些多重条件的逻辑判断代码
开放封闭原则
,易于切换算法,易于扩展- 将不同行为抽取到一个独立类层次结构中,并将原始类组合成同一个,从而减少重复代码,易于复用
缺点:
- 程序中会有较多策略类
适用范围
- 需要了解算法的不同点,才可以编写合适的策略类(即算法规则)
- 算法的使用与算法的实现分离开,也就是说,算法的上下文逻辑不是特别重要,这样才有分离的意义
策略模式的组成
一个策略模式至少由两部分组成。
- 第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。
- 第二个部分是环境类 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 = { isNonEmpty: function (value, errMsg) { if (value === '') { return errMsg; } }, minLenth: function (value, length, errMsg) { if (value.length < length) { return errMsg; } }, isMobile: function (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; } } 复制代码