javascript设计模式--策略模式之输入验证


Posted in Javascript onNovember 27, 2015

策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算饭的客户.

先定义一个简单的输入表单:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-">
    <style>
      .form{
        width: px;
        height: px;
        #margin: px auto;
      }
      .form-item-label{
        width:px;
        text-align: right;
        float: left;
      }
      .form-item-input{
        float: left;
      }
      .form-item{
        width: % ;
        height: px;
        line-height: px;
      }
    </style>
  </head>
  <body>
    <div class='form'>
      <div class="form-item">
        <div class='form-item-label'><span>用户名:</span></div>
        <div class='form-item-input'><input id='userName' name='用户名' type="text"></div>
      </div>
      <div class="form-item" >
        <div class='form-item-label'><span>密码:</span></div>
        <div class='form-item-input'><input id='password' name='密码' type="text"></div>
      </div>
      <div class="form-item" >
        <div class='form-item-label'><span>确认密码:</span></div>
        <div class='form-item-input'><input id='repassword' name='密码确认' type="text"></div>
      </div>
      <div class="form-item" >
        <div class='form-item-label'><span>邮箱:</span></div>
        <div class='form-item-input'><input id='mail' name='邮箱' type="text" ></div>
      </div>
    </div>
    <br>
    <button id='submit' >提交</button>
    <script type='text/javascript' src="../reference/jquery-...min.js"></script>
  </body>
</html>

 一般在页面上编辑信息后的提交动作中,都需要对输入的信息进行验证,会看到把很多负责check的代码写在提交函数中或者写在一个独立的check函数中。

比如像下面这样。      

$(document).ready(function(){
        $('#submit').bind('click', doSubmit);
      });
      function doSubmit(){
        var eleUserName = document.getElementById('userName');
        if(eleUserName.value === '') {
          alert('用户名不能为空');
          return;
        }
        if(eleUserName.length < 6) {
          alert('用户名长度不能少于6个字符');
          return;
        }
        if(eleUserName.length > 6) {
          alert('用户名长度不能多于20个字符');
          return;
        }
      }

这样的写法功能上肯定能满足要求,但是,会存在几个问题:

1.如果我要在其他页面上使用,那就要将代码进行复制,所谓的复用就变成了复制,代码会存在大量重复。好一点的会把check代码分类整理封装,单还会存在较多的重复复制。

2.如果我要增加一个输入验证,那么就要直接修改提交函数,该函数会显的臃肿,并且是破坏“开闭”原则的。

3.如果修改了提交函数,就要将函数设计的测试全都覆盖一遍,因为,不知道何时就会发生误改或者未知的情况。

改造步骤:

1.将每个验证逻辑看成是一个验证策略并封装成每个验证策略函数,函数参数保持一致,可以接受dom元素,被验证的值,错误消息,定制参数。

2.定义验证器,可将验证策略函数导入,也可以添加。

3.验证器提供验证方法,用于验证时的调用,其内部调用具体的验证策略函数。

4.验证调用。

步骤1.

把每一个if都看成一种校验的业务规则,把每种业务规则作为一个单独的策略函数,将所有的策略函数封装成一个策略对象。       

var validationStrategies = {
        isNoEmpty: function(element, errMsg, value) {
          if(value === '') {
            return this.buildInvalidObj(element, errMsg, value );
          }
        },
        minLength: function(element, errMsg, value, length) {
          if(value.length < length){
            return this.buildInvalidObj(element, errMsg, value);
          }
        },
        maxLength: function(element, errMsg, value, length) {
          if(value.length > length){
            return this.buildInvalidObj(element, errMsg, value);
          }
        },
        isMail: function(element, errMsg, value, length) {
          var reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
          if(!reg.test(value)){
            return this.buildInvalidObj(element, errMsg, value);
          }
        }
      };

所有函数的参数的前3个都保持一致,而且是必须的,表示被验证的DOM元素,错误消息,被验证的值,第4个开始由函数自身的验证规则决定定制的参数,可有多个参数。

“buildInvalidObj”方法只是把前3个参数打成一个错误对象进行返回,只要验证不通过就会返回这个错误对象。

根据依赖倒置原则,高层次的模块不应该依赖于低层次的模块,因此不能让验证的调用方直接使用。

通过验证器的方式进行封装和抽象。

步骤2:

定义验证器,可以将所有验证策略导入其内,也可以单独添加验证策略函数。         

//输入验证器
      function InputValidators(){
        this.validators = [];
        this.strategies = {};
      }
      //从策略对象导入验证策略函数
      //参数:
      // strategies: 包含各种策略函数的对象
      InputValidators.prototype.importStrategies = function(strategies) {
        for(var strategyName in strategies) {
          this.addValidationStrategy(strategyName, strategies[strategyName]);
        }
      };
      //添加验证策略函数
      //参数:
      // name: 策略名称
      // strategy: 策略函数
      InputValidators.prototype.addValidationStrategy = function(name, strategy){
        this.strategies[name] = strategy;
      };

步骤3:

添加验证方法,接受外部调用。

第一个参数rule,设置成验证规则,比如 "minLength:6",通过下面的代码会生成对具体策略函数的调用,调用会压到缓存中,等待一起调用。

":6"表示策略函数根据自身规则所定制的参数。     

//添加验证方法
      //参数:
      // rule: 验证策略字符串
      // element: 被验证的dom元素
      // errMsg: 验证失败时显示的提示信息
      // value: 被验证的值
      InputValidators.prototype.addValidator = function(rule, element, errMsg, value) {
        var that = this;
        var ruleElements = rule.split(":");
        this.validators.push(function() {
          var strategy = ruleElements.shift();
          var params = ruleElements;
          params.unshift(value);
          params.unshift(errMsg);
          params.unshift(element);
          return that.strategies[strategy].apply(that, params);
        });
      };

通过一个check函数来调用所有的验证。并将错误的结果进行返回。      

//开始验证
      InputValidators.prototype.check = function() {
        for(var i = 0, validator; validator = this.validators[i++];){
          var result = validator();
          if(result) {
            return result;
          }
        }
      };

步骤4:

在需要验证的地方,先new一个验证器对象。              

var validators = new InputValidators();

将包含验证策略函数的对象导入,或者单独添加验证策略函数。          

validators.importStrategies(validationStrategies);
        validators.addValidationStrategy('isEqual', function(element, errMsg, value1, value2) {
          if(value1 !== value2) {
            return this.buildInvalidObj(element, errMsg, value1 );
          }
        });

可以看出,不同的验证策略我们可以预先封装进策略对象中,也可以根据实际情况即时添加。

然后通过添加验证方法将需要验证的策略,被验证的dom元素,错误消息,被验证的值添加进验证器中,这样避免了直接调用策略对象,降低了耦合性。

var eleUserName = document.getElementById('userName');
validators.addValidator('isNoEmpty', eleUserName, '用户名不能为空', eleUserName.value);
validators.addValidator('minLength:6', eleUserName, '用户名的字符个数必须是6到20个', eleUserName.value);
validators.addValidator('maxLength:20', eleUserName, '用户名的字符个数必须是6到20个', eleUserName.value);
var elePassword = document.getElementById('password');
validators.addValidator('isNoEmpty', elePassword, '密码不能为空', elePassword.value);
validators.addValidator('minLength:6', elePassword, '密码的字符个数必须是6到20个', elePassword.value);
validators.addValidator('maxLength:20', elePassword, '密码的字符个数必须是6到20个', elePassword.value);
var eleRepassword = document.getElementById('repassword');
validators.addValidator('isNoEmpty', eleRepassword, '确认密码不能为空', eleRepassword.value);
validators.addValidator('minLength:6', eleRepassword, '确认密码的字符个数必须是6到20个', eleRepassword.value);
validators.addValidator('maxLength:20', eleRepassword, '确认密码的字符个数必须是6到20个', eleRepassword.value);
validators.addValidator('isEqual:' + elePassword.value, eleRepassword, '两次密码不一致', eleRepassword.value);
var eleMail = document.getElementById('mail');
validators.addValidator('isNoEmpty', eleMail, '邮箱不能为空', eleMail.value);
validators.addValidator('isMail', eleMail, '邮箱不是一个有效的格式', eleMail.value);

调用验证器的check执行所有的验证。            

var result = validators.check();
        if(result){
          alert(result.errMsg);
          result.element.focus();
          result.element.select();
          return false;
        }

check返回的是错误对象,我们可以在check后通过该对象统一地对DOM元素进行提示性操作,比如设置焦点,选中内容,或者为输入框外部包上一层红色的样式。

至此,可以看出通过策略模式的改在,输入验证时,我们只需要关心用哪个验证规则,采用什么样的提示性信息即可,不再暴露实现细节,方便调用,方便后续的扩展和组件化。

全部代码:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <style>
      .form{
        width: 400px;
        height: 200px;
        #margin: 0px auto;
      }
      .form-item-label{
        width:100px;
        text-align: right;
        float: left;
      }
      .form-item-input{
        float: left;
      }
      .form-item{
        width: 100% ;
        height: 50px;
        line-height: 50px;
      }
    </style>
  </head>
  <body>
    <div class='form'>
      <div class="form-item">
        <div class='form-item-label'><span>用户名:</span></div>
        <div class='form-item-input'><input id='userName' name='用户名' type="text"></div>
      </div>
      <div class="form-item" >
        <div class='form-item-label'><span>密码:</span></div>
        <div class='form-item-input'><input id='password' name='密码' type="text"></div>
      </div>
      <div class="form-item" >
        <div class='form-item-label'><span>确认密码:</span></div>
        <div class='form-item-input'><input id='repassword' name='密码确认' type="text"></div>
      </div>
      <div class="form-item" >
        <div class='form-item-label'><span>邮箱:</span></div>
        <div class='form-item-input'><input id='mail' name='邮箱' type="text" ></div>
      </div>
    </div>
    <br>
    <button id='submit' >提交</button>
    <script type='text/javascript' src="../reference/jquery-1.11.3.min.js"></script>
    <script type='text/javascript'>
      $(document).ready(function(){
        $('#submit').bind('click', doSubmit);
      });
function doSubmit(){
        var validators = new InputValidators();
        validators.importStrategies(validationStrategies);
        validators.addValidationStrategy('isEqual', function(element, errMsg, value1, value2) {
          if(value1 !== value2) {
            return this.buildInvalidObj(element, errMsg, value1 );
          }
        });
        var eleUserName = document.getElementById('userName');
        validators.addValidator('isNoEmpty', eleUserName, '用户名不能为空', eleUserName.value);
        validators.addValidator('minLength:6', eleUserName, '用户名的字符个数必须是6到20个', eleUserName.value);
        validators.addValidator('maxLength:20', eleUserName, '用户名的字符个数必须是6到20个', eleUserName.value);
        var elePassword = document.getElementById('password');
        validators.addValidator('isNoEmpty', elePassword, '密码不能为空', elePassword.value);
        validators.addValidator('minLength:6', elePassword, '密码的字符个数必须是6到20个', elePassword.value);
        validators.addValidator('maxLength:20', elePassword, '密码的字符个数必须是6到20个', elePassword.value);
        var eleRepassword = document.getElementById('repassword');
        validators.addValidator('isNoEmpty', eleRepassword, '确认密码不能为空', eleRepassword.value);
        validators.addValidator('minLength:6', eleRepassword, '确认密码的字符个数必须是6到20个', eleRepassword.value);
        validators.addValidator('maxLength:20', eleRepassword, '确认密码的字符个数必须是6到20个', eleRepassword.value);
        validators.addValidator('isEqual:' + elePassword.value, eleRepassword, '两次密码不一致', eleRepassword.value);
        var eleMail = document.getElementById('mail');
        validators.addValidator('isNoEmpty', eleMail, '邮箱不能为空', eleMail.value);
        validators.addValidator('isMail', eleMail, '邮箱不是一个有效的格式', eleMail.value);
        var result = validators.check();
        if(result){
          alert(result.errMsg);
          result.element.focus();
          result.element.select();
          return false;
        }
        alert('验证通过');
      }
      //输入验证器
      function InputValidators(){
        this.validators = [];
        this.strategies = {};
        //this.from(validationStrategies);
      }
      //添加验证方法
      //参数:
      // rule: 验证策略字符串
      // element: 被验证的dom元素
      // errMsg: 验证失败时显示的提示信息
      // value: 被验证的值
      InputValidators.prototype.addValidator = function(rule, element, errMsg, value) {
        var that = this;
        var ruleElements = rule.split(":");
        this.validators.push(function() {
          var strategy = ruleElements.shift();
          var params = ruleElements;
          params.unshift(value);
          params.unshift(errMsg);
          params.unshift(element);
          return that.strategies[strategy].apply(that, params);
        });
      };
      //添加验证策略函数
      //参数:
      // name: 策略名称
      // strategy: 策略函数
      InputValidators.prototype.addValidationStrategy = function(name, strategy){
        this.strategies[name] = strategy;
      };
      //从策略对象导入验证策略函数
      //参数:
      // strategies: 包含各种策略函数的对象
      InputValidators.prototype.importStrategies = function(strategies) {
        for(var strategyName in strategies) {
          this.addValidationStrategy(strategyName, strategies[strategyName]);
        }
      };
      //验证失败时,将相关的错误信息打包返回
      //参数:
      // element: dom元素
      //  errMsg: 验证失败时的提示消息
      //  value: 被验证的值
      InputValidators.prototype.buildInvalidObj = function(element, errMsg, value){
        return {
          'value': value,
          'element': element,
          'errMsg': errMsg
        };
      };
      //开始验证
      InputValidators.prototype.check = function() {
        for(var i = 0, validator; validator = this.validators[i++];){
          var result = validator();
          if(result) {
            return result;
          }
        }
      };
      //验证策略对象,包含默认的验证策略函数
      var validationStrategies = {
        isNoEmpty: function(element, errMsg, value) {
          if(value === '') {
            return this.buildInvalidObj(element, errMsg, value );
          }
        },
        minLength: function(element, errMsg, value, length) {
          if(value.length < length){
            return this.buildInvalidObj(element, errMsg, value);
          }
        },
        maxLength: function(element, errMsg, value, length) {
          if(value.length > length){
            return this.buildInvalidObj(element, errMsg, value);
          }
        },
        isMail: function(element, errMsg, value, length) {
          var reg = /^(\w-*\.*)+@(\w-?)+(\.\w{2,})+$/;
          if(!reg.test(value)){
            return this.buildInvalidObj(element, errMsg, value);
          }
        }
      };
    </script>
  </body>
</html>

以上所述是小编给大家介绍的javascript设计模式--策略模式之输入验证的全部内容,希望大家喜欢。

Javascript 相关文章推荐
MSN消息提示类
Sep 05 Javascript
JavaScript 模拟用户单击事件
Dec 31 Javascript
javascript实现百度地图鼠标滑动事件显示、隐藏
Apr 02 Javascript
node.js读取文件到字符串的方法
Jun 29 Javascript
JS模拟bootstrap下拉菜单效果实例
Jun 17 Javascript
BootStrap实现带有增删改查功能的表格(DEMO详解)
Oct 26 Javascript
微信小程序 wxapp内容组件 text详细介绍
Oct 31 Javascript
浅谈JavaScript的innerWidth与innerHeight
Oct 12 Javascript
浅谈Vue数据响应思路之数组
Nov 06 Javascript
浅谈Vue3.0之前你必须知道的TypeScript实战技巧
Sep 11 Javascript
jQuery操作动画完整实例分析
Jan 10 jQuery
vue组件讲解(is属性的用法)模板标签替换操作
Sep 04 Javascript
jQuery实现图片预加载效果
Nov 27 #Javascript
基于Jquery实现仿百度百科右侧导航代码附源码下载
Nov 27 #Javascript
jquery实现两边飘浮可关闭的对联广告
Nov 27 #Javascript
jquery关于事件冒泡和事件委托的技巧及阻止与允许事件冒泡的三种实现方法
Nov 27 #Javascript
JS实现的表格行鼠标点击高亮效果代码
Nov 27 #Javascript
基于jquery animate操作css样式属性小结
Nov 27 #Javascript
Javascript简单实现面向对象编程继承实例代码
Nov 27 #Javascript
You might like
索尼SONY ICF-7600A(W)电路分析
2021/03/01 无线电
浅谈php serialize()与unserialize()的用法
2013/06/05 PHP
windows下配置php5.5开发环境及开发扩展
2014/12/25 PHP
PHP使用反射机制实现查找类和方法的所在位置
2016/04/22 PHP
PHP实现的统计数据功能详解
2016/12/06 PHP
PHP实现批量删除(封装)
2017/04/28 PHP
PHP实现创建一个RPC服务操作示例
2020/02/23 PHP
javascript 遍历验证所有文本框的值
2009/08/27 Javascript
COM中获取JavaScript数组大小的代码
2009/11/22 Javascript
利用CSS、JavaScript及Ajax实现高效的图片预加载
2013/10/16 Javascript
浏览器图片选择预览、旋转、批量上传的JS代码实现
2013/12/04 Javascript
BootStrap 超链接变按钮的实现方法
2016/09/25 Javascript
Node.js使用supervisor进行开发中调试的方法
2019/03/26 Javascript
自定义Vue组件打包、发布到npm及使用教程
2019/05/22 Javascript
vue使用代理解决请求跨域问题详解
2019/07/24 Javascript
Vue + ts实现轮播插件的示例
2020/11/10 Javascript
[02:51]DOTA2英雄基础教程 风暴之灵
2013/12/23 DOTA
Django中实现一个高性能计数器(Counter)实例
2014/07/09 Python
Python检测网站链接是否已存在
2016/04/07 Python
Python微信公众号开发平台
2018/01/25 Python
python实现两个文件合并功能
2018/04/01 Python
使用python编写udp协议的ping程序方法
2018/04/22 Python
python验证码识别教程之灰度处理、二值化、降噪与tesserocr识别
2018/06/04 Python
详解Python中的format格式化函数的使用方法
2019/11/20 Python
python标准库sys和OS的函数使用方法与实例详解
2020/02/12 Python
Python matplotlib图例放在外侧保存时显示不完整问题解决
2020/07/28 Python
Python中logging日志记录到文件及自动分割的操作代码
2020/08/05 Python
[原创]赚疯了!转手立赚800+?大佬的python「抢茅台脚本」使用教程
2021/01/12 Python
基于canvas的骨骼动画的示例代码
2018/06/12 HTML / CSS
高中自我鉴定范文
2013/11/03 职场文书
营销人才自我鉴定范文
2013/12/25 职场文书
2014年安全生产大检查方案
2014/05/13 职场文书
《分数乘法》教学反思
2016/02/24 职场文书
村党总支部公开承诺书2016
2016/03/25 职场文书
MySQL运行报错:“Expression #1 of SELECT list is not in GROUP BY clause and contains nonaggre”解决方法
2022/06/14 MySQL
MySQL索引失效场景及解决方案
2022/07/23 MySQL