深入理解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 面向对象 function类
May 13 Javascript
IE6下通过a标签点击切换图片的问题
Nov 14 Javascript
javascript使用smipleChart实现简单图表
Jan 02 Javascript
原生javascript 学习之js变量全面了解
Jul 14 Javascript
实现React单页应用的方法详解
Aug 02 Javascript
JQuery实现文字无缝滚动效果示例代码(Marquee插件)
Mar 07 Javascript
详解让sublime text3支持Vue语法高亮显示的示例
Sep 29 Javascript
Vue实现购物车场景下的应用
Nov 27 Javascript
Node.js readline模块与util模块的使用
Mar 01 Javascript
js中document.write和document.writeln的区别
Mar 11 Javascript
vue生成token并保存到本地存储中
Jul 17 Javascript
这应该是最详细的响应式系统讲解了
Jul 22 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 stristr() 函数(不区分大小写的字符串查找)
2010/06/03 PHP
php 判断访客是否为搜索引擎蜘蛛的函数代码
2011/07/29 PHP
PHP中的多行字符串传递给JavaScript的两种方法
2014/06/19 PHP
PHP框架性能测试报告
2016/05/08 PHP
Laravel如何使用Redis共享Session
2018/02/23 PHP
PHP调用其他文件中的类
2018/04/02 PHP
PHP实现的权重算法示例【可用于游戏根据权限来随机物品】
2019/02/15 PHP
经典的解除许多网站无法复制文字的绝招
2006/12/31 Javascript
基于Jquery制作的幻灯片图集效果打包下载
2011/02/12 Javascript
Moment.js 不容错过的超棒Javascript日期处理类库
2012/04/15 Javascript
Javascript判断对象是否相等实现代码
2013/03/18 Javascript
javascript实现动态侧边栏代码
2014/02/19 Javascript
JavaScript获取图片真实大小代码实例
2014/09/24 Javascript
JavaScript检测实例属性, 原型属性
2015/02/04 Javascript
Angular表单验证实例详解
2016/10/20 Javascript
分分钟玩转Vue.js组件(二)
2017/03/01 Javascript
React Native验证码倒计时工具类分享
2017/10/24 Javascript
js代码规范之Eslint安装与配置详解
2018/09/08 Javascript
JavaScript ES6中的简写语法总结与使用技巧
2018/12/30 Javascript
详解基于webpack&gettext的前端多语言方案
2019/01/29 Javascript
vue-cli3使用mock数据的方法分析
2020/03/16 Javascript
基于Vue CSR的微前端实现方案实践
2020/05/27 Javascript
[02:10]探秘浦东源深体育馆 DOTA2 Supermajor不见不散
2018/05/17 DOTA
Python求出0~100以内的所有素数
2018/01/23 Python
使用Django启动命令行及执行脚本的方法
2018/05/29 Python
Pytorch反向求导更新网络参数的方法
2019/08/17 Python
django项目中使用云片网发送短信验证码的实现
2021/01/19 Python
新年爱情寄语
2014/04/08 职场文书
小学优秀班主任事迹材料
2014/05/17 职场文书
计划生育个人总结
2015/03/02 职场文书
学年个人总结范文
2015/03/05 职场文书
爱的教育观后感
2015/06/17 职场文书
2016春季校长开学典礼致辞
2015/11/26 职场文书
人生一定要学会的三样东西:放下、忘记、珍惜
2019/08/21 职场文书
Vue实现动态查询规则生成组件
2021/05/27 Vue.js
golang实现浏览器导出excel文件功能
2022/03/25 Golang