Welcome 微信登录

首页 / 脚本样式 / JavaScript / javascript设计模式--策略模式之输入验证

策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化独立于使用算饭的客户.
先定义一个简单的输入表单:
<!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设计模式--策略模式之输入验证的全部内容,希望大家喜欢。