深入理解JavaScript系列(33):设计模式之策略模式详解


Posted in Javascript onMarch 03, 2015

介绍

策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。

正文

在理解策略模式之前,我们先来一个例子,一般情况下,如果我们要做数据合法性验证,很多时候都是按照swith语句来判断,但是这就带来几个问题,首先如果增加需求的话,我们还要再次修改这段代码以增加逻辑,而且在进行单元测试的时候也会越来越复杂,代码如下:

        validator = {

            validate: function (value, type) {

                switch (type) {

                    case 'isNonEmpty ':

                        {

                            return true; // NonEmpty 验证结果

                        }

                    case 'isNumber ':

                        {

                            return true; // Number 验证结果

                            break;

                        }

                    case 'isAlphaNum ':

                        {

                            return true; // AlphaNum 验证结果

                        }

                    default:

                        {

                            return true;

                        }

                }

            }

        };

        //  测试

        alert(validator.validate("123", "isNonEmpty"));

那如何来避免上述代码中的问题呢,根据策略模式,我们可以将相同的工作代码单独封装成不同的类,然后通过统一的策略处理类来处理,OK,我们先来定义策略处理类,代码如下:
var validator = {
    // 所有可以的验证规则处理类存放的地方,后面会单独定义

    types: {},
    // 验证类型所对应的错误消息

    messages: [],
    // 当然需要使用的验证类型

    config: {},
    // 暴露的公开验证方法

    // 传入的参数是 key => value对

    validate: function (data) {
        var i, msg, type, checker, result_ok;
        // 清空所有的错误信息

        this.messages = [];
        for (i in data) {

            if (data.hasOwnProperty(i)) {
                type = this.config[i];  // 根据key查询是否有存在的验证规则

                checker = this.types[type]; // 获取验证规则的验证类
                if (!type) {

                    continue; // 如果验证规则不存在,则不处理

                }

                if (!checker) { // 如果验证规则类不存在,抛出异常

                    throw {

                        name: "ValidationError",

                        message: "No handler to validate type " + type

                    };

                }
                result_ok = checker.validate(data[i]); // 使用查到到的单个验证类进行验证

                if (!result_ok) {

                    msg = "Invalid value for *" + i + "*, " + checker.instructions;

                    this.messages.push(msg);

                }

            }

        }

        return this.hasErrors();

    },
    // helper

    hasErrors: function () {

        return this.messages.length !== 0;

    }

};

然后剩下的工作,就是定义types里存放的各种验证类了,我们这里只举几个例子:
// 验证给定的值是否不为空

validator.types.isNonEmpty = {

    validate: function (value) {

        return value !== "";

    },

    instructions: "传入的值不能为空"

};
// 验证给定的值是否是数字

validator.types.isNumber = {

    validate: function (value) {

        return !isNaN(value);

    },

    instructions: "传入的值只能是合法的数字,例如:1, 3.14 or 2010"

};
// 验证给定的值是否只是字母或数字

validator.types.isAlphaNum = {

    validate: function (value) {

        return !/[^a-z0-9]/i.test(value);

    },

    instructions: "传入的值只能保护字母和数字,不能包含特殊字符"

};

使用的时候,我们首先要定义需要验证的数据集合,然后还需要定义每种数据需要验证的规则类型,代码如下:
var data = {

    first_name: "Tom",

    last_name: "Xu",

    age: "unknown",

    username: "TomXu"

};
validator.config = {

    first_name: 'isNonEmpty',

    age: 'isNumber',

    username: 'isAlphaNum'

};

最后,获取验证结果的代码就简单了:
validator.validate(data);
if (validator.hasErrors()) {

    console.log(validator.messages.join("\n"));

}

总结

策略模式定义了一系列算法,从概念上来说,所有的这些算法都是做相同的事情,只是实现不同,他可以以相同的方式调用所有的方法,减少了各种算法类与使用算法类之间的耦合。

从另外一个层面上来说,单独定义算法类,也方便了单元测试,因为可以通过自己的算法进行单独测试。

实践中,不仅可以封装算法,也可以用来封装几乎任何类型的规则,是要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑是要策略模式来处理各种变化。

Javascript 相关文章推荐
IE网页js语法错误2行字符1、FF中正常的解决方法
Sep 09 Javascript
JavaScript获得url所有参数键值表的方法
Mar 21 Javascript
jQuery简单实现验证邮箱格式
Jul 15 Javascript
javascript中判断json的方法总结
Aug 27 Javascript
jquery常用函数与方法汇总
Sep 01 Javascript
微信小程序实现表单校验功能
Mar 30 Javascript
JS自定义函数实现时间戳转换成date的方法示例
Aug 27 Javascript
Three.js利用dat.GUI如何简化试验流程详解
Sep 26 Javascript
浅谈Vue数据响应思路之数组
Nov 06 Javascript
JS实现瀑布流效果
Mar 07 Javascript
Vue 样式切换及三元判断样式关联操作
Aug 09 Javascript
分享一个vue实现的记事本功能案例
Apr 11 Vue.js
JavaScript模拟重力状态下抛物运动的方法
Mar 03 #Javascript
深入理解JavaScript系列(31):设计模式之代理模式详解
Mar 03 #Javascript
深入理解JavaScript系列(30):设计模式之外观模式详解
Mar 03 #Javascript
深入理解JavaScript系列(29):设计模式之装饰者模式详解
Mar 03 #Javascript
jQuery对象与DOM对象之间的相互转换
Mar 03 #Javascript
深入理解JavaScript系列(28):设计模式之工厂模式详解
Mar 03 #Javascript
JS运动基础框架实例分析
Mar 03 #Javascript
You might like
PHP 动态随机生成验证码类代码
2010/04/09 PHP
php简单日历函数
2015/10/28 PHP
Javascript 验证上传图片大小[客户端]
2009/08/01 Javascript
JavaScript replace(rgExp,fn)正则替换的用法
2010/03/04 Javascript
分享27款非常棒的jQuery 表单插件
2011/03/28 Javascript
JS Map 和 List 的简单实现代码
2013/07/08 Javascript
用js一次改变多个input的readonly属性值的方法
2014/06/11 Javascript
jquery ui bootstrap 实现自定义风格
2014/11/14 Javascript
JavaScript中的操作符==与===介绍
2014/12/31 Javascript
jquery+html5烂漫爱心表白动画代码分享
2015/08/24 Javascript
javascript实现的网站访问量统计代码
2015/12/20 Javascript
学习JavaScript设计模式之观察者模式
2020/04/22 Javascript
jQuery简单获取键盘事件的方法
2016/01/22 Javascript
Vue.js实现在下拉列表区域外点击即可关闭下拉列表的功能(自定义下拉列表)
2017/05/30 Javascript
Vue数组更新及过滤排序功能
2017/08/10 Javascript
VUE DOM加载后执行自定义事件的方法
2018/09/07 Javascript
vue单页缓存方案分析及实现
2018/09/25 Javascript
js module大战
2019/04/19 Javascript
使用 js 简单的实现 bind、call 、aplly代码实例
2019/09/07 Javascript
vue利用全局导航守卫作登录后跳转到未登录前指定页面的实例代码
2020/05/19 Javascript
vue绑定数字类型 value为数字的实例
2020/08/31 Javascript
详解JavaScript 中的批处理和缓存
2020/11/19 Javascript
[01:06] DOTA2英雄背景故事第三期之秩序法则光之守卫
2020/07/07 DOTA
Python的Django框架中的数据库配置指南
2015/07/17 Python
Python的SimpleHTTPServer模块用处及使用方法简介
2018/01/22 Python
python通过txt文件批量安装依赖包的实现步骤
2019/08/13 Python
Python实现密码薄文件读写操作
2019/12/16 Python
Pytorch之卷积层的使用详解
2019/12/31 Python
Python面向对象程序设计之类和对象、实例变量、类变量用法分析
2020/03/23 Python
Python colormap库的安装和使用详情
2020/10/06 Python
波兰家具和室内装饰品购物网站:Vivre
2018/04/10 全球购物
印尼综合在线预订网站:Tiket.com(机票、酒店、火车、租车和娱乐)
2018/10/11 全球购物
Farfetch阿联酋:奢侈品牌时尚购物平台
2019/07/26 全球购物
数据管理员的自我评价分享
2013/11/15 职场文书
实习教师自我鉴定
2013/12/12 职场文书
反对四风问题自我剖析材料
2014/09/29 职场文书