demo3——策略模式

策略模式支持你的任务在运行时时自主选择算法。

需求描述

表单提交在应用中非常常见,因此,前端的表单验证(比如在表单提交之前验证用户名是否为空,email是否符合格式)会频繁出现。

在认识策略模式之前,你的选择可能是为每个表单写一个专门的验证函数,然后不断的复制代码(我也曾这样做过)。但是策略模式的出现完美的解决了这个问题,可以说,策略模式在前端的最大作用之一就是应用于表单验证了。使用策略模式,无论怎样的表单,都只需调用一个函数即可进行表单验证。

实现

假定有如下数据,来源于一段表单:

var data = {
            username : "xiaoMing",
            password : 'fkgrtwall',
            email : 'xiaoming7654@163.com',
        }

假定我们对数据的要求是:用户名长度在4位到16位之间,且由数字或字母组成。对密码的要求是长度要大于8位且不能为纯数字。对邮件要求则是符合邮件格式即可。

我们预期的效果是这样的:

//检测data中的数据是否合法,如果不合法则弹窗提示错误信息并返回false
validation.validate(data);

因此,我们需要建立validation对象,在validation对象中,我们需要内建一个对象来保存不同属性对应的验证算法。

var validation = {
            // 按照每项数据的类型来验证
            checkByType : {
                // 用户名验证
                username : function (value){
                    var res = {};
                    res.pass = (!/[^a-z0-9]/i.test(value) && value.length > 4 && value.length < 16);
                    if(value.length < 4){
                        res.msg = "用户名长度过短";
                    }else if(value.length > 16){
                        res.msg = "用户名长度过长";
                    }else if(/[^a-z0-9]/i.test(value)){
                        res.msg = "用户名只能由数字和字母组成";
                    }
                    return res;
                },
                // 邮箱验证
                email : function (value){
                    var res = {};
                    if(/^(\w){1,20}@(\w){1,10}((\.\w{1,8}){1,4})$/.test(value)){
                        res.pass = true;
                    }else{
                        res.pass = false;
                        res.msg = "邮箱格式不符合规范";
                    }
                    return res;
                },
                // 密码验证
                password : function (value){
                    var res = {};
                    if(/[^0-9]/i.test(value) && value.length > 8){
                        res.pass = true;
                    }else if(!/[^0-9]/i.test(value)){
                        res.msg = "密码不能均为数字";
                    }else{
                        res.msg = "密码长度不能短与8";
                    }
                    return res;
                }
            }
        };

通过上述代码可以看到,在内建对象checkByType中的每个方法都会根据检测结果返回一个对象,如果这个对象的pass值是false,则表示没有通过验证,还会有一个msg属性表示未通过的原因。我们还需在validation对象中创建另一个方法validate作为入口,该方法会遍历待检测对象的每一项,并调用相应的算法来检测。

validate : function (data){
                for(var index in data){
                    // 如果这项没有配置验证规则,则返回失败
                    if(!this.checkByType.hasOwnProperty(index)){
                        console.log(index + "尚未配置验证规则");
                        continue;
                    };
                    // 调用函数进行验证
                    var res = this.checkByType[index](data[index]);
                    // 当有一项验证不成功,则返回失败
                    if(!res.pass){
                        alert(res.msg);
                        return false;
                    }
                }
            }

完整的代码如下:

var validation = {
            // 验证数据的函数
            validate : function (data){
                for(var index in data){
                    // 如果这项没有配置验证规则,则返回失败
                    if(!this.checkByType.hasOwnProperty(index)){
                        console.log(index + "尚未配置验证规则");
                        continue;
                    };
                    // 调用函数进行验证
                    var res = this.checkByType[index](data[index]);
                    // 当有一项验证不成功,则返回失败,并弹窗显示失败原因
                    if(!res.pass){
                        alert(res.msg);
                        return false;
                    }
                }
            },
            // 按照每项数据的类型来验证
            checkByType : {
                // 用户名验证
                username : function (value){
                    var res = {};
                    res.pass = (!/[^a-z0-9]/i.test(value) && value.length > 4 && value.length < 16);
                    if(value.length < 4){
                        res.msg = "用户名长度过短";
                    }else if(value.length > 16){
                        res.msg = "用户名长度过长";
                    }else if(/[^a-z0-9]/i.test(value)){
                        res.msg = "用户名只能由数字和字母组成";
                    }
                    return res;
                },
                // 邮箱验证
                email : function (value){
                    var res = {};
                    if(/^(\w){1,20}@(\w){1,10}((\.\w{1,8}){1,4})$/.test(value)){
                        res.pass = true;
                    }else{
                        res.pass = false;
                        res.msg = "邮箱格式不符合规范";
                    }
                    return res;
                },
                // 密码验证
                password : function (value){
                    var res = {};
                    if(/[^0-9]/i.test(value) && value.length > 8){
                        res.pass = true;
                    }else if(!/[^0-9]/i.test(value)){
                        res.msg = "密码不能均为数字";
                    }else{
                        res.msg = "密码长度不能短与8";
                    }
                    return res;
                }
            }
        };

可以看到,这是一个通用的对象,你可以将它应用于整个项目中。随着验证对象的增多,验证规则也会变得更加丰富。之后对于每个新的表单,只需获取表单每一项的值并调用validation.validate方法,代码复用性非常强。