深入理解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 相关文章推荐
关于js中alert弹出窗口文本换行问题简单详细说明
Dec 11 Javascript
jquery 无限级下拉菜单的简单实现代码
Feb 21 Javascript
Iframe实现跨浏览器自适应高度解决方法
Sep 02 Javascript
jQuery中odd选择器的定义和用法
Dec 23 Javascript
JQuery中属性过滤选择器用法实例分析
May 18 Javascript
jQuery中 delegate使用的问题
Jul 03 Javascript
JS阻止事件冒泡行为和闭包的方法
Jun 16 Javascript
javascript弹出窗口中增加确定取消按钮
Jun 24 Javascript
js微信分享API
Oct 11 Javascript
AngularJS 工作原理详解
Aug 18 Javascript
vue3.0 CLI - 2.3 - 组件 home.vue 中学习指令和绑定
Sep 14 Javascript
利用weixin-java-miniapp生成小程序码并直接返回图片文件流的方法
Mar 29 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 数组遍历的差异(array_diff 的实现)
2008/03/23 PHP
javascript add event remove event
2008/04/07 Javascript
js left,right,mid函数
2008/06/10 Javascript
javascript 写类方式之九
2009/07/05 Javascript
尝试在让script的type属性等于text/html
2013/01/15 Javascript
extjs两个tbar问题探讨
2013/08/08 Javascript
js动态添加表格数据使用insertRow和insertCell实现
2014/05/22 Javascript
解决checkbox的attr(checked)一直为undefined问题
2014/06/16 Javascript
js+csss实现的一个带复选框的下拉框
2014/09/29 Javascript
JS实现倒计时和文字滚动的效果实例
2014/10/29 Javascript
jQuery中animate用法实例分析
2015/03/09 Javascript
Javascript实现颜色rgb与16进制转换的方法
2015/04/18 Javascript
jquery+css实现简单的图片轮播效果
2017/08/07 jQuery
JS实现简单短信验证码界面
2017/08/07 Javascript
javascript 作用于作用域链的详解
2017/09/27 Javascript
手机浏览器唤起微信分享(JS)
2020/10/11 Javascript
为什么推荐使用JSX开发Vue3
2020/12/28 Vue.js
python实现多线程的方式及多条命令并发执行
2016/06/07 Python
python+flask编写一个简单的登录接口
2020/11/13 Python
html5的canvas方法使用指南
2014/12/15 HTML / CSS
关键字final的用法
2013/10/02 面试题
什么是Smart Navigation?
2016/07/03 面试题
四川internet信息高速公路(C#)笔试题
2012/02/29 面试题
车工岗位职责
2013/11/26 职场文书
建筑人员岗位职责
2013/12/25 职场文书
应届生简历中的自我评价
2014/01/13 职场文书
在校硕士自我鉴定
2014/01/23 职场文书
学术会议主持词
2014/03/17 职场文书
企业宗旨标语
2014/06/10 职场文书
工程承包协议书范本
2014/09/29 职场文书
2015年勤工助学工作总结
2015/04/29 职场文书
2019年亲子运动会口号
2019/10/11 职场文书
JavaScript嵌入百度地图API的最详细方法
2021/04/16 Javascript
MySQL Threads_running飙升与慢查询的相关问题解决
2021/05/08 MySQL
js基础语法与maven项目配置教程案例
2021/07/15 Javascript
方法汇总:Python 安装第三方库常用
2022/04/26 Python