首页 > 代码库 > 策略者模式

策略者模式

 1. 策略模式定义和优点 

  策略者模式: 定义一系列的算法 把它们一个个封装起来 并使他们可以相互替换。优点:

     A) 策略模式利用组合 委托等思想 有效避免很多if条件语句。
     B) 策略模式提供了开发——封闭原则 使代码更容易理解和扩展。
     C) 策略模式中的代码可以复用。

 2. 策略模式的使用

  使用策略模式计算奖金 

  公司的年终奖是根据员工的工资和绩效来考核的,绩效为A的人,年终奖为工资的4倍,绩效为B的人,年终奖为工资的3倍,绩效为C的人,年终奖为工资的2倍;现在我们使用一般的编码方式会如下这样编写代码:

  技术分享

   缺点如下: 

   A) calculateBouns 函数包含了很多if else

    B) calcualteBouns 函数缺乏弹性 假如还有D等级 那么我们还需要在calculateBouns函数中添加盘算等级D的if语句

   C) 算法复用性差 如果在其他地方也有类似这样的算法 但是规则不一样 这么我们的代码不能通用。

  策略模式

  技术分享

 3. 表单验证

  我们经常要进行表单验证 比如注册登录对话框 我们登录之前要进行验证操作比如:

  A) 用户名不能为空

  B) 密码长度不能小于6

  C) 手机号码必须符合格式

  技术分享

  我之前的写法

  技术分享  

  但是这样编写代码有如下缺点:

  1. registerForm.onsubmit 函数比较大,代码中包含了很多if语句;
  2. registerForm.onsubmit 函数缺乏弹性,如果增加了一种新的效验规则,或者想把密码的长度效验从6改成8,我们必须改registerForm.onsubmit 函数内部的代码。违反了开放-封闭原则
  3. 算法的复用性差,如果在程序中增加了另外一个表单,这个表单也需要进行一些类似的效验,那么我们可能又需要复制代码了;

    策略模式来重构表单校验。

  第一步封装策略对象

    技术分享

  第二步: 准备实现Validator类,Validator类在这里作为Context,负责接收用户的请求并委托给strategy 对象

  技术分享   

  Validator类在这里作为Context,负责接收用户的请求并委托给strategys对象。上面的代码中,我们先创建一个Validator对象,然后通过validator.add方法往validator对象中添加一些效验规则,validator.add方法接收3个参数,如下代码:

validator.add(registerForm.password,’minLength:6′,’密码长度不能小于6位’);

  registerForm.password 为效验的input输入框dom节点;

  minLength:6: 是以一个冒号隔开的字符串,冒号前面的minLength代表客户挑选的strategys对象,冒号后面的数字6表示在效验过程中所必须验证的参数,minLength:6的意思是效验 registerForm.password 这个文本输入框的value最小长度为6位;如果字符串中不包含冒号,说明效验过程中不需要额外的效验信息;

  第三个参数是当效验未通过时返回的错误信息;

  

  当我们往validator对象里添加完一系列的效验规则之后,会调用validator.start()方法来启动效验。如果validator.start()返回了一个errorMsg字符串作为返回值,说明该次效验没有通过,此时需要registerForm.onsubmit方法返回false来阻止表单提交.

  技术分享

  如果我们既要效验输入框是否为空,还要效验输入框的长度不要小于10位的话,那么我们期望需要像如下传递参数:

   技术分享

 最后上一张全部代码

  

 1 // 策略对象 2 var strategys = { 3     isNotEmpty: function(value,errorMsg) { 4         if(value =http://www.mamicode.com/== ‘‘) { 5             return errorMsg; 6         } 7     }, 8     // 限制最小长度 9     minLength: function(value,length,errorMsg) {10         if(value.length < length) {11             return errorMsg;12         }13     },14     // 手机号码格式15     mobileFormat: function(value,errorMsg) {16         if(!/(^1[3|5|8][0-9]{9}$)/.test(value)) {17             return errorMsg;18         }19     } 20 };21 var Validator = function(){22     this.cache = [];  // 保存效验规则23 };24 Validator.prototype.add = function(dom,rules) {25     var self = this;26     for(var i = 0, rule; rule = rules[i++]; ){27         (function(rule){28             var strategyAry = rule.strategy.split(":");29             var errorMsg = rule.errorMsg;30             self.cache.push(function(){31                 var strategy = strategyAry.shift();32                 strategyAry.unshift(dom.value);33                 strategyAry.push(errorMsg);34                 return strategys[strategy].apply(dom,strategyAry);35             });36         })(rule);37     }38 };39 Validator.prototype.start = function(){40     for(var i = 0, validatorFunc; validatorFunc = this.cache[i++]; ) {41     var msg = validatorFunc(); // 开始效验 并取得效验后的返回信息42     if(msg) {43         return msg;44     }45     }46 };47 // 代码调用48 var registerForm = document.getElementById("registerForm");49 var validateFunc = function(){50     var validator = new Validator(); // 创建一个Validator对象51     /* 添加一些效验规则 */52     validator.add(registerForm.userName,[53         {strategy: ‘isNotEmpty‘,errorMsg:‘用户名不能为空‘},54         {strategy: ‘minLength:6‘,errorMsg:‘用户名长度不能小于6位‘}55     ]);56     validator.add(registerForm.password,[57         {strategy: ‘minLength:6‘,errorMsg:‘密码长度不能小于6位‘},58     ]);59     validator.add(registerForm.phoneNumber,[60         {strategy: ‘mobileFormat‘,errorMsg:‘手机号格式不正确‘},61     ]);62     var errorMsg = validator.start(); // 获得效验结果63     return errorMsg; // 返回效验结果64 };65 // 点击确定提交66 registerForm.onsubmit = function(){67     var errorMsg = validateFunc();68     if(errorMsg){69         alert(errorMsg);70         return false;71     }72 }

策略者模式