策略模式(Strategy)
Oct 27, 2022 ·
3 Min Read
策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
解析:就是定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。在客户对 Context 发起请求的时候,Context 总是把请求委托给这些策略对象中间的某一个进行计算。
使用场景:
- 校验器
- 缓动动画
- 可替换的计算
将不变的部分和变化的部分分隔开是每个设计模式的主题。
策略模式的目的就是将算法的使用与算法的实现分离开来。
比如:
在我们不使用设计模式的情况下,总会这么写:
const calculateBonus = function(performanceLevel, salary){ if(performanceLevel === 'S') { return salary * 4; } if(performanceLevel === 'A') { return salary * 3; } if(performanceLevel === 'B') { return salary * 2; }}calculateBonus('B', 20000);calculateBonus('S', 6000);
缺点:
- 包含太多
if-else
语句。 - 缺乏弹性,如果需要增加多个等级的时候,需要深入函数内部实现。
- 算法复用性差。
使用策略模式下:
const strategies = { S: function(salary) { return salary * 4; }, A: function(salary) { return salary * 3; }, B: function(salary) { return salary * 2; }}
const calculateBonus = function(level, salary){ return strategies[level](salary);}
calculateBonus('S', 20000);
若要增加其他等级,直接修改 strategies
即可,调用完全不用改。
例如:使用策略模式实现一个表单检验器validator
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>Title</title></head><body><form action="/xxx" id="resForm" method="post"> 姓名:<input type="text" name="username" placeholder="请输入你的姓名"> 密码:<input type="password" name="pwd" placeholder="请输入你的密码"> 手机号码:<input type="text" name="phone" placeholder="请输入你的手机号码"> <button>提交</button></form>
<script> const resForm = document.getElementById('resForm') resForm.addEventListener('submit', function () { const errMsg = validatFunc() alert(errMsg) if (errMsg) { return false } })
const validationRules = { isNonEmpty: function (value, errMsg) { if (value === '') { return errMsg } }, minLength: function (value, length, errMsg) { if (value.length < length) { return errMsg } }, isPhone: function (value, errMsg) { const phoneRE = /^(13[0-9]|14[5|7]|15[0|1|2|3|4|5|6|7|8|9]|18[0|1|2|3|5|6|7|8|9])\d{8}$/; if (phoneRE.test(value)) { return errMsg } } }
class Validator { constructor() { this.cache = []; }
add(dom, rules) { rules.forEach(rule => { let arr = rule.type.split(':'); const errMsg = rule.errMsg;
this.cache.push(() => { const type = arr.shift(); arr.unshift(dom.value); arr.push(errMsg);
return validationRules[type].apply(dom, arr); }) }) }
start() { for (let i = 0, validatorFunc; validatorFunc = this.cache[i++];) { const errorMsg = validatorFunc(); if (errorMsg) { return errorMsg; } } } }
const validatFunc = function () { const validator = new Validator();
validator.add(resForm.username, [{ type: 'isNonEmpty', errMsg: '姓名不能为空' }, { type: 'minLength:2', errMsg: '姓名不能少于2位' }])
validator.add(resForm.pwd, [{ type: 'isNonEmpty', errMsg: '密码不能为空' }, { type: 'minLength:2', errMsg: '密码不能少于6位' }])
validator.add(resForm.phone, [{ type: 'isPhone', errMsg: '请输入正确的手机号码' }])
const errMsg = validator.start(); return errMsg }</script></body></html>
Last edited Feb 15