深入理解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 jQuery中的DOM操作
Mar 21 Javascript
JS 遮照层实现代码
Mar 31 Javascript
js window.print实现打印特定控件或内容
Sep 16 Javascript
jquery实现动态操作select选中
Feb 11 Javascript
JavaScript操作class和style样式代码详解
Feb 13 Javascript
javascript实现简单计算器效果【推荐】
Apr 19 Javascript
js实现登录验证码
Dec 22 Javascript
Angular2使用Angular-CLI快速搭建工程(二)
May 21 Javascript
微信小程序实现折叠面板
Jan 31 Javascript
关于vue-cli 3配置打包优化要点(推荐)
Apr 22 Javascript
JavaScript使用表单元素验证表单的示例代码
Aug 20 Javascript
Angular8 简单表单验证的实现示例
Jun 03 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
DedeCms模板安装/制作概述
2007/03/11 PHP
基于ubuntu下nginx+php+mysql安装配置的具体操作步骤
2013/04/28 PHP
php实现在新浪云中使用imagick生成缩略图并上传的方法
2016/09/26 PHP
jQuery getJSON 处理json数据的代码
2010/07/26 Javascript
js实现在字符串中提取数字
2013/11/05 Javascript
js setTimeout()函数介绍及应用以倒计时为例
2013/12/12 Javascript
js 去除字符串第一位逗号的方法
2014/06/07 Javascript
JavaScript仿静态分页实现方法
2015/08/04 Javascript
对jQuary选择器的全面总结
2016/06/20 Javascript
利用vue-router实现二级菜单内容转换
2016/11/30 Javascript
JS去除重复并统计数量的实现方法
2016/12/15 Javascript
深入掌握 react的 setState的工作机制
2017/09/27 Javascript
详解适配器在JavaScript中的体现
2018/09/28 Javascript
vue-router权限控制(简单方式)
2018/10/29 Javascript
angular组件间传值测试的方法详解
2020/05/07 Javascript
vue3自定义dialog、modal组件的方法
2021/01/04 Vue.js
python 3.6 tkinter+urllib+json实现火车车次信息查询功能
2017/12/20 Python
python使用turtle绘制分形树
2018/06/22 Python
如何用Python合并lmdb文件
2018/07/02 Python
Python将一个CSV文件里的数据追加到另一个CSV文件的方法
2018/07/04 Python
对pyqt5中QTabWidget的相关操作详解
2019/06/21 Python
Pycharm 2019 破解激活方法图文详解
2019/10/11 Python
Python生成器常见问题及解决方案
2020/03/21 Python
Python sql注入 过滤字符串的非法字符实例
2020/04/03 Python
Window版下在Jupyter中编写TensorFlow的环境搭建
2020/04/10 Python
利用django创建一个简易的博客网站的示例
2020/09/29 Python
HTML5实践-图片设置成灰度图
2012/11/12 HTML / CSS
html5教程画矩形代码分享
2013/12/04 HTML / CSS
BIFFI美国站:意大利BIFFI BOUTIQUES豪华多品牌时装零售公司
2020/02/11 全球购物
一套软件测试笔试题
2014/07/25 面试题
高中生学习生活的自我评价
2013/11/27 职场文书
王老吉广告词
2014/03/20 职场文书
干部个人考察材料
2014/12/24 职场文书
2015年派出所民警工作总结
2015/04/24 职场文书
python 实现mysql自动增删分区的方法
2021/04/01 Python
Python中的程序流程控制语句
2022/02/24 Python