策略模式在表单验证中的应用
在任何一个系统里面,几乎都缺少不了提交表单的过程,比如注册、登陆、下订单等等。这篇文章就阐述了如何编写看着舒服的表单验证代码。
1、问题
相信大家平时再做表单验证的时候基本与如下代码相同:
if(input1.value === ''){
alert('xxx不能为空');
return false;
}else if(input2.length < 6){
alert('xxx最少6个字符');
return false;
}else if(...){
...
return false;
}
这样编写代码,的确能够完成业务的需求,能够完成表单的验证,但是存在很多问题,比如:
1、代码中包含太多的 if - else 语句,如果验证规则较多的话,看上去太过于恶心……
2、验证规则不可复用,如果我们另外一个页面也需要验证相似的表单,我们唯一的做法就是,复制一份,粘贴过去……
3、代码不易维护,不需要解释了吧……
2、解决办法
所谓办法总比问题多,办法是有的,比如马上要讲解的使用 策略模式 使表单验证更优雅更完美,我相信很多人很抵触设计模式,一听设计模式就觉得很遥远,觉得自己在工作中很少用到设计模式,那么你就错了,特别是js这种灵活的语言,有的时候你已经在你的代码中使用了设计模式,只是你不知道而已。更多关于设计模式的东西,以后会陆续写博客描述,这里只希望大家抛弃设计模式神秘的感觉,通俗的讲,它无非就是完成一件事情通用的办法而已。
3、畅想
回到正题,假如我们不想使用过多的 if - else 语句,那么我们心中比较理想的代码编写方式是什么呢?我们能不能像编写配置一样的去做表单验证呢?再来一个”一键验证“的功能,是不是很爽?答案是肯定的,所以我们心中理想的编写代码的方式如下:
// 获取表单form元素
var form = document.getElementById('f1');
// 创建表单校验实例
var validation = new Formvalidation(VerifiPolicy);
// 编写校验配置
validation.add(form.username, 'isNoEmpty', '用户名不能为空');
validation.add(form.password, 'minLength: 6', '密码长度不能小于6个字符');
validation.add(form.code, 'isMobile', '请填写正确的手机号');
// 开始校验,并接收错误信息
var errorMsg = validation.start();
// 如果有错误信息输出,说明校验未通过
if(errorMsg){
// 做一些其他的事
return false;
}
怎么样?感受感受,是不是看上去优雅多了?好了,有了心中的畅想,我们就可以向目标迈进了,下一步就要了解了解什么事策略模式了。
4、策略模式
策略模式,单纯的看它的名字”策略“,指的是做事情的方法,比如你从北京到哈尔滨(为什么到哈尔滨呢?因为我老家是哈尔滨的[偷笑]),你可以有几种策略供选择:
1、飞机,嗖嗖嗖直接就到了,节省时间。
2、火车,可以选择高铁出行,专为飞机恐惧症者提供。
3、徒步,不失为一个锻炼身体的选择。
4、other method……
所以,做一件事你会有很多方法,也就是所谓的策略,而我们今天要讲的策略模式也就是这个意思,它的核心思想是,将做什么和谁去做相分离。所以,一个完整的策略模式要有两个类,一个是策略类,一个是环境类(主要类),环境类接收请求,但不处理请求,它会把请求委托给策略类,让策略类去处理,而策略类的扩展是很容易的,这样,使得我们的代码易于扩展。
在表单验证的例子中,各种验证的方法组成了策略类,比如:判断是否为空的方法(如:isNoEmpty),判断最小长度的方法(如:minLength),判断是否为手机号的方法(isMobule)等等,他们组成了策略类,供给环境类去委托请求。下面,我们就来实战一下。
5、编写策略类
策略类很简单,它是由一组验证方法组成的对象,即策略对象
// 策略对象
var VerifiPolicy = {
// 判断是否为空
isNoEmpty : function(value, errorMsg){
if(value == ''){
return errorMsg;
}
},
// 判断最小长度
minLength : function(value, length, errorMsg){
if(value.length < length){
return errorMsg;
}
},
// 判断是否为手机号
isMobile : function(value, errorMsg){
if(!/(^1[3|5|8][0-9]{9}$)/.test(value)){
return errorMsg;
}
}
// 其他
}
6、编写环境类
根据我们的畅想,我们使用add方法添加验证配置,如下:
validation.add(form.username, 'isNoEmpty', '用户名不能为空');
add方法接受三个参数,第一个参数是表单字段,第二个参数是策略对象中策略方法的名字,第三个参数是验证未通过的错误信息。
然后使用 start 方法开始验证,若验证未通过,返回验证错误信息,如下:
var errorMsg = validation.start();
另外,再解释一下下面这句代码:
validation.add(form.password, 'minLength: 6', '密码长度不能小于6个字符');
add方法第一个参数我们说过了,是要验证的表单元素,第二个参数是一个字符串,使用 冒号(:) 分割,前面是策略方法名称,后面是传给这个方法的参数,第三个参数仍然是错误信息,我们希望完成这样的代码,废话不多说,直接上代码,如下:
// 构造函数
var Formvalidation = function(VerifiPolicy){
// 保存策略对象
this.strategies = VerifiPolicy;
// 验证缓存
this.validationFns = [];
}
// add 方法
Formvalidation.prototype.add = function(dom, rule, errorMsg){
var ary = rule.split(':');
var arg = [];
var self = this;
this.validationFns.push(function(){
arg = []; // 重置参数
var ruleName = ary[0]; // 策略对象方法名
// 组装参数
arg.push(dom.value);
if(ary[1]){
arg.push(ary[1]);
}
arg.push(errorMsg);
// 调用策略函数
return self.strategies[ruleName].apply(dom, arg);
});
}
// 开始验证
Formvalidation.prototype.start = function(){
for(var i = 0; ; i++){
var msg = this.validationFns[i]();
if(msg){
return msg;
}
}
}
至此,一个最简单的应用就完成了,另外你还可以对这个环境类进行扩展,比如支持复选框、单选框等表单的验证,还可以支持一个表单多规则的验证方式,总之,只要你觉得可以,就ok。程序世界从来都欢迎创造,去发挥你的想象吧。