策略模式中的策略就是一种算法或者业务规则,将这些策略作为函数进行封装,并向外提供统一的调用执行。

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

<!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></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>

转载于:https://www.cnblogs.com/kongxianghai/p/4985122.html

javascript设计模式实践之策略模式--输入验证相关推荐

  1. JavaScript设计模式之发布-订阅模式(观察者模式)-Part1

    <JavaScript设计模式与开发实践>读书笔记. 发布-订阅模式又叫观察者模式,它定义了对象之间的一种一对多的依赖关系.当一个对象的状态发生改变时,所有依赖它的对象都将得到通知. 例如 ...

  2. javascript设计模式实践之模板方法--具有百叶窗切换图片效果的JQuery插件(二)...

    在上一篇<javascript设计模式实践之迭代器--具有百叶窗切换图片效果的JQuery插件(一)>里,通过采用迭代器模式完成了各初始化函数的定义和调用. 接下来就要完成各个切换效果的编 ...

  3. 设计模式 ( 十八 ) 策略模式Strategy(对象行为型)

    设计模式 ( 十八 ) 策略模式Strategy(对象行为型) 1.概述 在软件开发中也经常遇到类似的情况,实现某一个功能有多种算法或者策略,我们能够依据环境或者条件的不同选择不同的算法或者策略来完毕 ...

  4. 设计模式入门(策略模式)

    [0]README 0.1)本文部分文字描述转自 "head first 设计模式",旨在学习 设计模式入门(策略模式) 的基础知识: 0.2)本文章节4和5的source cod ...

  5. javascript设计模式之装饰器模式(结构型模式)

    javascript设计模式之装饰器模式 js的设计模式分为创建型模式,结构型模式和行为模式 结构模式描述了如何组合对象以提供新的功能. 装饰器模式是一种常见的结构型模式,我们可以以一个基础对象为基础 ...

  6. Javascript设计模式之中介者模式

    前言:菜鸡也有梦想,而我的梦想就是进一个真正的互联网大厂.以前学习的时候没有系统的整理,从今天开始要保持每周写博客的习惯,希望自己可以有所成长.为了培养编程思维,决定从设计模式开始写起.我是通过读&l ...

  7. JS设计模式三:策略模式

    官方:策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户. 策略模式是常用的模式,例如jQuery的 $(selector).animate(st ...

  8. 再起航,我的学习笔记之JavaScript设计模式23(中介者模式)

    中介者模式 概念介绍 中介者模式(Mediator):通过中介者对象封装一系列对象之间的交互,使对象之间不再相互引用降低他们之间的耦合,有时中介者对象也可以改变对象之间的交互. 创建一个中介 中介者模 ...

  9. 设计模式のStrategyPattern(策略模式)----行为模式

    一.问题产生背景 当我们进行一系列处理时(员工工资核算,会员管理,计算器,优惠活动),会有很多相似的算法和处理过程,只是由于具体的算法的差异,导致必须不同处理.这些处理和客户端无关,我们可以把这些算法 ...

  10. Head First Design Mode(2)-设计模式入门(策略模式)

    该系列文章系个人读书笔记及总结性内容,任何组织和个人不得转载进行商业活动! 设计模式入门: 欢迎来到设计模式世界: 我们会看到设计模式的用途和优点,再看看关键的OO原则,通过实例来了解模式是如何运作的 ...

最新文章

  1. mysql物理文件组成
  2. YOLOv3 Darknet安装编译与训练自己的数据集
  3. [COGS58] 延绵的山峰
  4. pSort CodeForces - 28B(并查集)
  5. CAS的安装与配置(一)服务器端配置
  6. RabbitMQ如何解决被重复消费和数据丢失的问题?
  7. 3D MAX导出插件编写
  8. JDK8的新特性——Lambda表达式
  9. asterisk queue 队列
  10. python input函数用法mac_sublime text3解决input()函数无法使用的问题(Python)
  11. Ansible Tower:安装以及HA多集群安装
  12. EMOS部署及管理和部署EMOS邮件服务器
  13. NOI OJ 1.3 13:反向输出一个三位数 C语言
  14. selenium 模拟登录qq空间
  15. DFT频谱泄漏的数学分析及不产生泄漏的条件
  16. Android开发之EditText属性详解
  17. 上位机PC控制UR3机器人实现方式
  18. 11. 深度学习实践:实践方法论
  19. 循环神经网络模型及应用,循环神经网络应用举例
  20. 霸榜巨作、阿里内部顶级专家整理(Redis 5设计与源码分析)

热门文章

  1. html th width无效 解决方法
  2. 微信也QQ服务器,妄想山海QQ区还是微信区好 平民服务器选择推荐
  3. java alert 乱码_在servlet中输出JS中文乱码,servlet中alert对话框出现中文乱码的解决方法...
  4. JavaSE——Java8之Stream流
  5. 基于springboot的考研学习平台
  6. 多关键字排序的c语言编程,常见排序——“计数排序(三关键字)”的源程序(C语言版)...
  7. 2008服务器文件共享,2008服务器文件共享
  8. 7-17 mmh学长的三色灯 (20分)
  9. 3)Thymeleaf th:* 设置/修改属性值详解
  10. Android 表单之 EditText(输入框)详解