深入理解JavaScript系列(33):设计模式之策略模式(转)
介绍
策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。
正文
在理解策略模式之前,我们先来一个例子,一般情况下,如果我们要做数据合法性验证,很多时候都是按照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系列
http://www.cnblogs.com/TomXu/archive/2012/03/05/2358552.html
深入理解JavaScript系列(33):设计模式之策略模式(转)的更多相关文章
- JavaScript中的设计模式:策略模式
无论学习前端还是后端设计模式是作为一名程序员不可缺少的知识,就像下底传中对于一个边锋来说. 一.策略模式 策略模式给人的第一感觉就是在代码里面消除了很多if-else分支语句,比如一个求员工奖金的程序 ...
- 【javascript】javasrcipt设计模式之策略模式
策略模式支持在运行时由使用者选择合适的算法,对于使用者而言不用关心背后的具体事项,而使用者自动根据当前程序执行的上下文和配置,从已有的算法列表中选择出合适的算法来处理当前任务. 1.要解决的问题 2. ...
- PHP设计模式之策略模式
前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...
- 深入理解JavaScript系列(33):设计模式之策略模式
介绍 策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户. 正文 在理解策略模式之前,我们先来一个例子,一般情况下,如果我们要做数据合法性验证,很 ...
- 深入理解JavaScript系列(41):设计模式之模板方法
介绍 模板方法(TemplateMethod)定义了一个操作中的算法的骨架,而将一些步骤延迟到子类中.模板方法使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤. 模板方法是一种代码复用的 ...
- 深入理解JavaScript系列(38):设计模式之职责链模式
介绍 职责链模式(Chain of responsibility)是使多个对象都有机会处理请求,从而避免请求的发送者和接受者之间的耦合关系.将这个对象连成一条链,并沿着这条链传递该请求,直到有一个对象 ...
- 深入理解JavaScript系列(36):设计模式之中介者模式
介绍 中介者模式(Mediator),用一个中介对象来封装一系列的对象交互.中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互. 主要内容来自:http://www ...
- 深入理解JavaScript系列(30):设计模式之外观模式
介绍 外观模式(Facade)为子系统中的一组接口提供了一个一致的界面,此模块定义了一个高层接口,这个接口值得这一子系统更加容易使用. 正文 外观模式不仅简化类中的接口,而且对接口与调用者也进行了解耦 ...
- 深入理解JavaScript系列(31):设计模式之代理模式
介绍 代理,顾名思义就是帮助别人做事,GoF对代理模式的定义如下: 代理模式(Proxy),为其他对象提供一种代理以控制对这个对象的访问. 代理模式使得代理对象控制具体对象的引用.代理几乎可以是任何对 ...
随机推荐
- 浅谈OCR之Onenote 2010
原文:浅谈OCR之Onenote 2010 上一次我们讨论了Tesseract OCR引擎的用法,作为一款老牌的OCR引擎,目前已经开源,最新版本3.0中更是加入了中文OCR功能,再加上Google的 ...
- 【Android每周专题】触摸屏事件
本系列文章均为A2BGeek原创,转载务必在明显处注明: 转载自A2BGeek的[Android每周专题]系列,原文链接:http://blog.csdn.net/benbmw2008/article ...
- 自己动手写了第三阶段的处理器——教学OpenMIPS处理器蓝图
我们会继续上传新书<自己动手写处理器>(未公布).今天是第十条.我每星期试试4 从本章開始将一步一步地实现教学版OpenMIPS处理器.本章给出了教学版OpenMIPS的系统蓝图,首先介绍 ...
- 单服务器防护linux iptables脚本
#!/bin/bashiptables -Fiptables -P INPUT DROPiptables -P OUTPUT ACCEPTiptables -P FORWARD DROP/sbin/i ...
- 使用NFS安装oracle软件
昨天.使用openfiler创建nas存储系统,安装oracle软件,在所有正面最好,要创建一个数据库时报ora错,原来使用nfs安装oracle数据库,mount选项有特殊要求,如以下.以备查: R ...
- HashMap-死锁导致cpu占用100%分析(转)
最近项目里面的一段千年代码出了问题,这个问题以前也出现过,不过不是那么明显,这次迁移机器由以前的4台机子变成2台以后问题被放大,最终不得不解决,特此分析一下. 先放出问题的代码 ? 1 2 3 4 5 ...
- MYSQL中的字符串连接符
update `table` set nsdf = concat('a','b') where id=137
- mysql-定时调用存储过程
mysql定时调用存储过程,对表数据集表结构进行备份 存储过程实例: BEGIN DECLARE tname varchar(64); set @tname = CONCAT('RENAME TABL ...
- restrictkeyword
今天在移植ffmpeg到opencore时出现一个编译错误: /libavcodec/dsputil.c:545: error: expected ';', ',' or ')' before 'bl ...
- Windows Phone开发(38):动画之PointAnimation
原文:Windows Phone开发(38):动画之PointAnimation PointAnimation也是很简单的,与前面说到的两个Animation是差不多的,属性也是一样的,如By.Fro ...