策略模式
定义:定义一系列的算法,把它们一个个封装起来,并且使它们之间可以相互替换
将不变的部分和变化的部分分隔开是每个设计模式的主题,策略模式的目的就是将使用的算法和算法的实现分离开来
使用策略模式计算奖金
-
绩效为S的人奖金为4倍工资,A为3倍,B为2倍,要求提供一段代码,方便地计算每个员工的奖金
-
//策略对象 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); } console.log(calculateBonus('S',1000));//4000 console.log(calculateBonus('A',1000));//3000
表单验证(多种校验规则)
- 添加多种校验,如:既能校验它是否为空,又能校验输入文本长度
策略对象
-
const strategies={ //验证表单是否为空 isNonEmpty:function(value,errMsg){ console.log(value,errMsg); if(value=='') return errMsg; }, //验证文本长度 minLength: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; } };
Validator类
-
定义一个cache存放所有的验证函数
-
//Validator类 const Validator=function(){ this.cache=[]; }
Validator.prototype.add(dom,rules)
——添加验证规则
-
遍历rules数组,每个rule是由strategy和errMsg属性组成的对象
-
取出每个rule的strategy
('isNonEmpty'||'minLength:10')
和errMsg属性值 -
将每个验证函数(使用apply改变this指向dom)push进this.cache中,等到调用start()的时候再逐个调用
-
Validator.prototype.add=function(dom,rules){ const self=this; for(let i=0,rule;rule=rules[i++];){ (function(rule){ const strategyAry=rule.strategy.split(':'); const errMsg=rule.errMsg; self.cache.push(function(){ const strategy =strategyAry.shift(); strategyAry.unshift(dom.value); strategyAry.push(errMsg); return strategies[strategy].apply(dom,strategyAry); }) })(rule); } }
Validator.prototype.start()
——开启验证
-
遍历this.cache,逐个验证,若errMsg有值则说明表单验证失败,返回错误信息errMsg
-
Validator.prototype.start=function(){ for(let i=0,validatorFunc;validatorFunc=this.cache[i++];){ var errMsg=validatorFunc(); if(errMsg) return errMsg; } };
客户调用代码
-
<form action="#"> 用户名:<input type="text" name='userName'/> 密码:<input type="text" name="password"/> 手机号:<input type="text" name="phoneNumber"> <button id='btn'>提交</button> </form>
-
const registerForm=document.querySelector('form'); const validataFunc=function(){ const validator=new Validator(); //添加用户名验证 validator.add(registerForm.userName,[{ strategy:'isNonEmpty', errMsg:'用户名不能为空' }]); //添加密码验证 validator.add(registerForm.password,[{ strategy:'isNonEmpty', errMsg:'密码不能为空' },{ strategy:'minLength:10', errMsg:'密码长度不能小于10位' }]); //添加手机号验证 validator.add(registerForm.phoneNumber,[{ strategy:'isNonEmpty', errMsg:'手机号不能为空' },{ strategy:'isMobile', errMsg:'手机号格式错误' }]); const errMsg=validator.start(); if(errMsg) return errMsg; } registerForm.onsubmit=function(){ const errMsg=validataFunc(); if(errMsg){ alert(errMsg); return false;//阻止表单提交 } }
策略模式的优缺点
优点:
- 利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句
- 提供了对开放-封闭原则的完美支持,将算法封装在独立的strategy中,易于切换、易于理解、易于扩展
- 策略模式中的算法也可以复用在其他地方,避免多重赋值粘贴
- 利用组合和委托让Context拥有执行算法的能力,也是继承的一种轻便的替代方案
缺点:
- 程序中增加了许多策略类和策略对象(实际上比把它们负责的逻辑堆砌在Context中要好)
- 要使用策略模式,必须了解虽有的strategy,strategy要向客户暴露它所有的实现,这是违反最少知识原则的