深入理解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 相关文章推荐
用 JSON 处理缓存
Apr 27 Javascript
20个非常有用的PHP类库 加速php开发
Jan 15 Javascript
javascript权威指南 学习笔记之null和undefined
Sep 25 Javascript
JavaScript-RegExp对象只能使用一次问题解决方法
Jun 23 Javascript
JS实现的表格操作类详解(添加,删除,排序,上移,下移)
Dec 22 Javascript
jQuery弹层插件jquery.fancybox.js用法实例
Jan 22 Javascript
javaScript中定义类或对象的五种方式总结
Dec 04 Javascript
ES6正则的扩展实例详解
Apr 25 Javascript
react router 4.0以上的路由应用详解
Sep 21 Javascript
微信小程序实现跳转的几种方式总结(推荐)
Apr 24 Javascript
vue v-for直接循环数字实例
Nov 07 Javascript
Vue 的双向绑定原理与用法揭秘
May 06 Javascript
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一次性删除前台checkbox多选内容的方法
2013/09/22 PHP
php中autoload的用法总结
2013/11/08 PHP
PHP中把stdClass Object转array的几个方法
2014/05/08 PHP
php数组索引与键值操作技巧实例分析
2015/06/24 PHP
深入浅析Yii admin的权限控制
2016/08/31 PHP
PHP编程实现微信企业向用户付款的方法示例
2017/07/26 PHP
php支付宝系列之电脑网站支付
2018/05/30 PHP
PHP中“=>
2019/03/01 PHP
基于jquery的一个OutlookBar类,动态创建导航条
2010/11/19 Javascript
jquery.map()方法的使用详解
2015/07/09 Javascript
学习JavaScript设计模式(封装)
2015/11/26 Javascript
jquery.masonry瀑布流效果
2017/05/25 jQuery
微信小程序实现倒计时60s获取验证码
2020/04/17 Javascript
详解Vue微信公众号开发踩坑全记录
2017/08/21 Javascript
node.js将MongoDB数据同步到MySQL的步骤
2017/12/10 Javascript
Vue组件之自定义事件的功能图解
2018/02/01 Javascript
react高阶组件添加和删除props
2019/04/26 Javascript
[01:04:08]完美世界DOTA2联赛PWL S3 INK ICE vs GXR 第一场 12.16
2020/12/18 DOTA
Python编程中实现迭代器的一些技巧小结
2016/06/21 Python
python3编码问题汇总
2016/09/06 Python
python链接oracle数据库以及数据库的增删改查实例
2018/01/30 Python
关于Python作用域自学总结
2019/06/10 Python
通过pycharm使用git的步骤(图文详解)
2019/06/13 Python
学习Python需要哪些工具
2020/09/04 Python
Redbubble法国:由独立艺术家设计的独特产品
2019/01/08 全球购物
城市规划毕业生求职信
2013/10/10 职场文书
校运会广播稿100字
2014/01/27 职场文书
数学兴趣小组活动总结
2014/07/08 职场文书
2014年党风建设工作总结
2014/11/19 职场文书
作文评语怎么写
2014/12/25 职场文书
司考复习计划
2015/01/19 职场文书
幼儿园园长安全责任书
2015/05/08 职场文书
民事起诉书范本
2015/05/19 职场文书
准备去美国留学,那么大学申请文书应该怎么写?
2019/08/12 职场文书
Python爬虫基础讲解之请求
2021/05/13 Python
浅谈@Value和@Bean的执行顺序问题
2021/06/16 Java/Android