策略模式
定义:定义一系列的算法,把他们一个个封装起来,并且使他们可以相互替换。
组成:一个策略模式的程序至少由两部分组成。
-
第一部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。
-
第二部分是环境类Context,Context接受客户的请求,随后把请求委托给一个策略类。
Context中要维持对摸个策略对象的引用。
JavaScript版本的策略模式
场景1:员工的工资基数和年底绩效发放情况,绩效为S的人年终奖有4倍工资,绩效为A的人年终奖有3倍工资,而绩效为B的人年终奖是2倍工资。
// 策略类 var strategies = { "S":function(salary){ return salary * 4 } "A":function(salary){ return salary * 3 } "B":function(salary){ return salary * 2 } } // 环境类 var calculateBonus = function(level,salary){ return strategies[level](salary) } console.log(calculateBonus('S',20000)) // 输出:80000 console.log(calculateBonus('A',10000)) // 输出:30000
实际开发中,策略模式可以用来封装"业务规则"。
场景2:表单验证,注册页面,点击注册按钮之前,有如下几条校验逻辑:
-
用户名不能为空
-
密码长度不能少于6位
-
手机号码必须符合格式
var strategies = { isNonEmpty:function(value,errorMsg){ // 不为空 if(value ==== ''){ return errorMsg; } }, minLength:function(value,length,errorMsg){ // 限制最小长度 if(value.length<length){ return errorMsg; } }, isMobile:function(value,errorMsg){ // 手机号码格式 if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){ return errorMsg; } } }
var Validator = function(){ this.cache = []; // 保存校验规则 } Validator.prototype.add = function(dom,rule,errorMsg){ var ary = rule.split(':'); // 把strategy和参数分开 this.cache.push(function(){ // 把校验的步骤用空函数包装起来,并且放入cache var strategy = ary.shift() // 用户挑选的strategy ary.unshift(dom.value) // 把input的value添加进参数列表 ary.push(errorMsg) // 把errorMsg添加进参数列表 return strategies[strategy].apply(dom,ary) }) } Validator.prototype.start = function(){ for(var i = 0,validatorFunc;validatorFuc = this.cache[i++];){ var msg = validatorFun(); // 开始校验,并取得校验后的返回信息 if(msg){ return msg; } } }
// 校验 validator.add(registerForm.userName,'isNonEmpty','用户名不能为空') validator.add(registerForm.userName,'minLength:10','用户名长度不能小于10位')
给一个文本输入框对应多种校验规则??p84
策略模式的优缺点
优点
-
策略模式利用组合、委托和多态等技术和思想,可以有效避免多重条件选择语句
-
对开放-封闭原则的支持,将算法封装在独立的策略对象中,易于切换,易于理解,易于扩展
-
算法可以复用到系统的其他地方,避免许多复制粘贴工作
-
利用组合和委托让Context拥有执行算法的能力,这也是继承的一种更轻便的替代方案
缺点
-
会在程序中增加许多策略类和策略对象
-
使用策略模式必须要了解所有的策略对象,策略对象要向客户暴露它所有的实现,违反了最少知识原则
去掉策略类,如何实现策略模式
var S = function(salary){ return salary * 4 } var A = function(salary){ return salary * 3 } var B = function(salary){ return salary * 2 } var calculateBonus = function(func,salary){ return func(salary) } calculateBonus(S,10000) // 输出40000
在JavaScript的策略模式中,策略类往往被函数所替代,这时策略模式就成为一种“隐性”的模式