深入理解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的一个OutlookBar类,动态创建导航条
Nov 19 Javascript
JS实现三个层重叠点击互相切换的方法
Oct 06 Javascript
jquery validate表单验证插件
Sep 06 Javascript
简单理解vue中track-by属性
Oct 26 Javascript
Vue.js实现简单ToDoList 前期准备(一)
Dec 01 Javascript
使用canvas及js简单生成验证码方法
Apr 02 Javascript
手把手教你写一个微信小程序(推荐)
Oct 17 Javascript
Node.js JSON模块用法实例分析
Jan 04 Javascript
小程序getLocation需要在app.json中声明permission字段
Apr 04 Javascript
Vue2.x通用条件搜索组件的封装及应用详解
May 28 Javascript
微信小程序自定义单项选择器样式
Jul 25 Javascript
解决vue打包 npm run build-test突然不动了的问题
Nov 13 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
再次研究下cache_lite
2007/02/14 PHP
PHP中error_reporting()函数的用法(修改PHP屏蔽错误)
2011/07/01 PHP
Yii2实现中国省市区三级联动实例
2017/02/08 PHP
php实现的统计字数函数定义与使用示例
2017/07/26 PHP
JavaScript TO HTML 转换
2006/06/26 Javascript
JavaScript写的一个自定义弹出式对话框代码
2010/01/17 Javascript
解析javascript系统错误:-1072896658的解决办法
2013/07/08 Javascript
jquery获取div距离窗口和父级dv的距离示例
2013/10/10 Javascript
简单的代码实现jquery定时器
2013/11/17 Javascript
通过url查找a元素应用案例
2014/04/29 Javascript
Javascript基础教程之for循环
2015/01/18 Javascript
js创建对象的方法汇总
2016/01/07 Javascript
详解JavaScript数组过滤相同元素的5种方法
2017/05/23 Javascript
node.js中npm包管理工具用法分析
2020/02/14 Javascript
vue3.0中使用element的完整步骤
2021/03/04 Vue.js
Python 对象中的数据类型
2017/05/13 Python
使用Turtle画正螺旋线的方法
2017/09/22 Python
对python numpy数组中冒号的使用方法详解
2018/04/17 Python
python docx 中文字体设置的操作方法
2018/05/08 Python
python 实现将字典dict、列表list中的中文正常显示方法
2018/07/06 Python
Python Flask前后端Ajax交互的方法示例
2018/07/31 Python
Python面向对象基础入门之设置对象属性
2018/12/11 Python
Python实现对字典分别按键(key)和值(value)进行排序的方法分析
2018/12/19 Python
pytorch  网络参数 weight bias 初始化详解
2020/06/24 Python
Python如何输出警告信息
2020/07/30 Python
Html5新增标签有哪些
2017/04/13 HTML / CSS
外企求职信范文分享
2013/12/31 职场文书
令人印象深刻的自荐信
2014/05/25 职场文书
四风查摆问题及整改措施
2014/10/10 职场文书
2015年试用期工作总结
2014/12/12 职场文书
工作年限证明范本
2015/06/15 职场文书
护理培训心得体会
2016/01/22 职场文书
2016年政治理论学习心得体会
2016/01/25 职场文书
2019公司管理制度
2019/04/19 职场文书
python基础之停用词过滤详解
2021/04/21 Python
MySQL添加索引特点及优化问题
2022/07/23 MySQL