深入理解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 相关文章推荐
基于jquery的loading效果实现代码
Nov 05 Javascript
jquery衣服颜色选取插件效果代码分享
Aug 28 Javascript
jQuery实现仿QQ在线客服效果的滚动层代码
Oct 15 Javascript
JS使用eval解析JSON的注意事项分析
Nov 14 Javascript
理解Angular数据双向绑定
Jan 10 Javascript
jquery.form.js框架实现文件上传功能案例解析(springmvc)
May 26 Javascript
js设置和获取自定义属性的方法
Oct 20 Javascript
angularjs中ng-attr的用法详解
Dec 31 Javascript
简单实现js倒计时功能
Feb 13 Javascript
js数字计算 误差问题的快速解决方法
Feb 28 Javascript
微信小程序自定义键盘 内部虚拟支付
Dec 20 Javascript
Vue 组件修改根实例的数据的方法
Apr 02 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
真正的ZIP文件操作类(php)
2007/07/21 PHP
php从完整文件路径中分离文件目录和文件名的方法
2015/03/13 PHP
php将字符串转换成16进制的方法
2015/03/17 PHP
Laravel中基于Artisan View扩展包创建及删除应用视图文件的方法
2016/10/08 PHP
laravel-admin 在列表页添加自定义按钮的例子
2019/09/30 PHP
从新浪弄下来的全屏广告代码 与使用说明
2007/03/15 Javascript
用jQuery技术实现Tab页界面之二
2009/09/21 Javascript
javascript 读取XML数据,在页面中展现、编辑、保存的实现
2009/10/27 Javascript
js弹出层之1:JQuery.Boxy (二)
2011/10/06 Javascript
JS格式化数字保留两位小数点示例代码
2013/10/15 Javascript
JQuery EasyUI 日期控件如何控制日期选择区间
2014/05/05 Javascript
jQuery满屏焦点图左右滚动特效代码分享
2015/09/07 Javascript
Bootstarp风格的toggle效果分享
2016/02/23 Javascript
JavaScript的React Web库的理念剖析及基础上手指南
2016/05/10 Javascript
Js apply方法详解
2017/02/16 Javascript
关于JavaScript的单双引号嵌套问题
2017/08/20 Javascript
JavaScript实现开关等效果
2017/09/08 Javascript
python抓取京东价格分析京东商品价格走势
2014/01/09 Python
Python的Flask框架中配置多个子域名的方法讲解
2016/06/07 Python
常见的python正则用法实例讲解
2016/06/21 Python
使用python Fabric动态修改远程机器hosts的方法
2018/10/26 Python
Python 利用切片从列表中取出一部分使用的方法
2019/02/01 Python
Django框架组成结构、基本概念与文件功能分析
2019/07/30 Python
python的等深分箱实例
2019/11/22 Python
python实现智能语音天气预报
2019/12/02 Python
python通过文本在一个图中画多条线的实例
2020/02/21 Python
Python内置方法和属性应用:反射和单例(推荐)
2020/06/19 Python
AmazeUI底部导航栏与分享按钮的示例代码
2020/08/18 HTML / CSS
Coggles美国/加拿大:高级国际时装零售商
2018/10/23 全球购物
.net软件工程师面试题
2015/03/31 面试题
软件配置管理有什么好处
2015/04/15 面试题
财务部总监岗位职责
2014/03/12 职场文书
继承公证书样本
2014/04/04 职场文书
乡镇党委书记第三阶段个人整改措施
2014/09/16 职场文书
个人四风对照检查材料
2014/09/26 职场文书
英语通知范文
2015/04/22 职场文书