深入理解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 相关文章推荐
JavaScript 对话框和状态栏使用说明
Oct 25 Javascript
获取dom元素那些讨厌的位置封装代码
Jun 23 Javascript
jQuery 1.7.2中getAll方法的疑惑分析
May 23 Javascript
基于jQuery实现模拟页面加载进度条
Apr 01 Javascript
document.compatMode的CSS1compat使用介绍
Apr 03 Javascript
AngularJS页面访问时出现页面闪烁问题的解决
Mar 06 Javascript
Javascript中获取浏览器类型和操作系统版本等客户端信息常用代码
Jun 28 Javascript
javascript 判断是否是微信浏览器的方法
Oct 09 Javascript
Javascript typeof与instanceof的区别
Oct 18 Javascript
JS前端知识点 运算符优先级,URL编码与解码,String,Math,arguments操作整理总结
Jun 27 Javascript
Vue.set 全局操作简单示例
Sep 19 Javascript
Vue过滤器,生命周期函数和vue-resource简单介绍
Jan 12 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增删改查示例自己写的demo
2013/09/04 PHP
PHP数据库操作二:memcache用法分析
2017/08/16 PHP
yii2.0整合阿里云oss的示例代码
2017/09/19 PHP
Opacity.js
2007/01/22 Javascript
Display SQL Server Version Information
2007/06/21 Javascript
基于jQuery的history历史记录插件
2010/12/11 Javascript
CSS中position属性之fixed实现div居中
2015/12/14 Javascript
ionic3实战教程之随机布局瀑布流的实现方法
2017/12/28 Javascript
javascript填充默认头像方法
2018/02/22 Javascript
JavaScript执行环境及作用域链实例分析
2018/08/01 Javascript
微信小程序开发背景图显示功能
2018/08/08 Javascript
微信小程序实现tab左右切换效果
2020/11/15 Javascript
webstorm中配置Eslint的两种方式及差异比较详解
2018/10/19 Javascript
vue实现PC端录音功能的实例代码
2019/06/05 Javascript
Vue实现商品分类菜单数量提示功能
2019/07/26 Javascript
vue element-ui读取pdf文件的方法
2019/11/26 Javascript
使用webpack搭建vue环境的教程详解
2019/12/31 Javascript
基于js实现判断浏览器类型代码实例
2020/07/17 Javascript
Tornado 多进程实现分析详解
2018/01/12 Python
使用python中的in ,not in来检查元素是不是在列表中的方法
2018/07/06 Python
Django中日期处理注意事项与自定义时间格式转换详解
2018/08/06 Python
在windows下使用python进行串口通讯的方法
2019/07/02 Python
python 串口读取+存储+输出处理实例
2019/12/26 Python
Python爬虫爬取博客实现可视化过程解析
2020/06/29 Python
PyCharm vs VSCode,作为python开发者,你更倾向哪种IDE呢?
2020/08/17 Python
墨西哥巴士车票在线购买:ClickBus
2018/03/27 全球购物
自动化专业本科毕业生求职信
2013/10/20 职场文书
无故旷工检讨书
2014/01/26 职场文书
申请任职学生会干部自荐书范文
2014/02/13 职场文书
小学庆六一活动总结
2014/08/28 职场文书
高中运动会广播稿
2014/09/16 职场文书
音乐教师求职信范文
2015/03/20 职场文书
大学生党课心得体会
2016/01/07 职场文书
话题作文之学会尊重
2019/12/16 职场文书
Python实现抖音热搜定时爬取功能
2022/03/16 Python
python实现一个简单的贪吃蛇游戏附代码
2022/06/28 Python