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 相关文章推荐
用javascript实现点击链接弹出&quot;图片另存为&quot;而不是直接打开
Aug 15 Javascript
jQuery中jqGrid分页实现代码
Nov 04 Javascript
获取鼠标在div中的相对位置的实现代码
Dec 30 Javascript
javascript检测是否联网的实现代码
Sep 28 Javascript
JQuery判断checkbox是否选中及其它复选框操作方法合集
Jun 01 Javascript
在浏览器中打开或关闭JavaScript的方法
Jun 03 Javascript
jQuery实现信息提示框(带有圆角框与动画)效果
Aug 07 Javascript
JS实现的自定义水平滚动字体插件完整实例
Jun 17 Javascript
JavaScript reduce和reduceRight详解
Oct 24 Javascript
基于Layer+jQuery的自定义弹框
May 26 Javascript
JavaScript原生数组Array常用方法
Apr 06 Javascript
精读《Vue3.0 Function API》
May 20 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
PHP HTML代码串截取代码
2008/12/29 PHP
tp5.1 框架路由操作-URL生成实例分析
2020/05/26 PHP
jquery 应用代码 方便的排序功能
2010/02/06 Javascript
js中各浏览器中鼠标按键值的差异
2011/04/07 Javascript
js创建子窗口并且回传值示例代码
2013/07/02 Javascript
JS 页面计时器示例代码
2013/10/28 Javascript
jquery插件之定时查询待处理任务数量
2014/05/01 Javascript
flash+jQuery实现可关闭及重复播放的压顶广告
2015/04/15 Javascript
使用JavaScript判断用户输入的是否为正整数(两种方法)
2017/02/05 Javascript
JS中静态页面实现微信分享功能
2017/02/06 Javascript
微信小程序 定位到当前城市实现实例代码
2017/02/23 Javascript
xmlplus组件设计系列之选项卡(Tabbar)(5)
2017/05/03 Javascript
[02:29]完美世界高校联赛上海赛区回顾
2015/12/15 DOTA
python抓取京东商城手机列表url实例代码
2013/12/18 Python
在Python下使用Txt2Html实现网页过滤代理的教程
2015/04/11 Python
Python中的字符串替换操作示例
2016/06/27 Python
python 脚本生成随机 字母 + 数字密码功能
2018/05/26 Python
基于python绘制科赫雪花
2018/06/22 Python
浅谈python str.format与制表符\t关于中文对齐的细节问题
2019/01/14 Python
python读csv文件时指定行为表头或无表头的方法
2019/06/26 Python
Python利用WMI实现ping命令的例子
2019/08/14 Python
python中matplotlib条件背景颜色的实现
2019/09/02 Python
python 实现二维字典的键值合并等函数
2019/12/06 Python
python实现替换word中的关键文字(使用通配符)
2020/02/13 Python
Python抓包程序mitmproxy安装和使用过程图解
2020/03/02 Python
在python中实现求输出1-3+5-7+9-......101的和
2020/04/02 Python
python设置表格边框的具体方法
2020/07/17 Python
PyTorch 中的傅里叶卷积实现示例
2020/12/11 Python
Photobook澳大利亚:制作相片书,婚礼卡,旅行相簿
2017/01/12 全球购物
SISLEY希思黎官方旗舰店:享誉全球的奢华植物美容品牌
2018/04/25 全球购物
使用C#编写创建一个线程的代码
2013/01/22 面试题
机关出纳岗位职责
2014/04/03 职场文书
优秀管理者事迹材料
2014/05/22 职场文书
2015年为民办实事工作总结
2015/05/26 职场文书
清洁工工作总结
2015/08/11 职场文书
MYSQL 的10大经典优化案例场景实战
2021/09/14 MySQL