【JavaScript设计模式】行为型设计模式--策略模式
来源:互联网 发布:mac文件打包怎么做 编辑:程序博客网 时间:2024/06/05 07:46
俗话说“条条大路通罗马”。在现实中,很多时候也有多种途径可以到达同一个目的地,比如,我们要去某个地方旅游,可以根据具体的实际情况来选择出行的线路。在程序设计中,我们也常常遇到类似的情况,要实现某一个功能有多种方案可以选择。比如要对一个数组进行排序,我们可以选择快速排序算法,也可以选择冒泡排序算法。
策略模式定义了算法家族,分别封装起来,让他们之间可以互相替换,此模式让算法的变化不会影响到使用算法的客户。当然这些算法灵活多样,而且可以随意相互替换。这种方案呢,就是本文将要介绍的策略模式。
贴上策略模式的官方定义:
策略模式指的是定义一些列的算法,把他们一个个封装起来,并且使他们可以相互替换。目的就是将算法的使用与算法的实现分离开来。
从定义上看,策略模式就是用来封装算法的。但如果把策略模式仅仅用来封装算法,未免有点大材小用。在实际开发中,我们通常会把算法的含义扩散开来,使策略模式也可以用来封装一系列的“业务规则”。只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以使用策略模式来封装他们。
接下来想用一个表单校验的算法进行说明这个模式。
在一个Web项目中,注册、登录、修改用户信息等功能的实现都离不开提交表单。
假设我们正在编写一个注册的页面,在点击注册之前,有如下几条校验逻辑。
- 用户名不能为空;
- 密码长度不能少于6位;
- 手机号码必须符合格式。
1、表单校验的第一个版本
<!DOCTYPE html><html lang="en"><head> <meta charset="UTF-8"> <title>register</title></head><body><form id="registerForm" method="post" action="http://###.com/register"> <label for="userName">请输入用户名:</label> <input type="text" name="userName" id="userName"> <label for="pwd">请输入密码:</label> <input type="text" name="password" id="pwd"> <label for="phoneNumber">请输入密码:</label> <input type="text" name="phoneNumber" id="phoneNumber"> <input type="button" value="提交"></form><script> var registerForm = document.getElementById("registerForm"); registerForm.onsubmit = function(){ if( registerForm.userName.value === ''){ alert("用户名不能为空!"); return false; } if( registerForm.pwd.value.length < 6){ alert("密码长度不能少于6位!"); return false; } if( !/(^1[3|5|8][0-9]{9}$)/.test(registerForm.phoneNumber.value)){ alert("手机号码格式不正确!"); return false; } }</script></body></html>解析:
1) registerForm.onsubmit 函数比较庞大,包含了很多if语句,这些语句需要覆盖所有的校验规则;
2) registerForm.onsubmit 函数缺乏弹性,如果增加了一个新的校验规则,或者想把密码的长度校验从6变成8,我们都必须深入这个函数的内部实现,这违反了开放-封闭原则;
3)算法的复用性差,如果程序中增加另外一个表单,比如登录,这个表单也需要进行一些类似的校验,那么我们很可能只是复制一下这段代码,然后相对应的进行修改,造成的后果就是相似的代码到处都有,不利于代码的维护与美观。
那么,为了解决以上出现的这些问题,我们可以采用策略模式重构这个表单校验。
2、用策略模式重构表单校验
在重构代码的第一步就是将这些校验进行封装成策略对象。
//利用策略模式 var strategies = { //不为空 isNonEmpty: function ( value, errorMsg){ if( value === ''){ return errorMsg; } }, //最小长度 minLength: function ( value, length, errorMsg){ if( value.length < length){ return errorMsg; } }, //手机号码格式 isMobile: function ( value, errorMsg){ if( !/(^1[3|5|8][0-9]{9}$)/.test(value) ){ return errorMsg; } } };接下来,我们需要实现Validator类,负责接收用户的请求并委托给strategy对象。在实现Validator类的代码之前,我们先了解下用户是如何向Validator类发送请求的。
var validataFunc = function () { var validator = new Validator(); //创建一个Validator对象 validator.add( registerForm.userName, 'isNonEmpty', '用户名不能为空'); validator.add( registerForm.password, 'minLength:6', '密码长度不能少于6位'); validator.add( registerForm.phoneNumber, 'isMobile', '手机格式不正确'); var errorMsg = validator.start(); //获得校验结果 return errorMsg; //返回校验结果 }; var registerForm = document.getElementById("registerForm"); registerForm.onsubmit = function (){ var errorMsg = validataFunc(); if(errorMsg){ alert(errorMsg); return false; //阻止表单提交 } };解析:
- 我们首先创建了一个 Validator对象,然后通过validator.add()方法往对象中添加一些校验规则,这个方法接受3个参数。
- validator.add( registerForm.userName, 'isNonEmpty', '用户名不能为空'); 其中registerForm.userName为参与校验的input输入框; 'isNonEmpty'为名字的校验参数;'用户名不能为空'是当校验未通过时返回的错误信息。
最后一部分是Validator类的实现:
var Validator = function () { this.cache = []; }; Validator.prototype.add = function (dom, rule, errorMsg) { var ary = rule.split(':'); this.cache.push(function () { var strategy = ary.shift(); ary.unshift(dom.value); ary.push(errorMsg); return strategies[strategy].apply(dom,ary); }); }; Validator.prototype.start = function (){ for( var i = 0,validataFunc;validataFunc = this.cache[ i++]; ){ var msg = validataFunc(); if(msg){ return msg; } } };
使用策略模式重构代码之后,我们仅仅通过“配置”的方式就可以完成一个表达的校验,而且这些校验规则也可以复用在程序中的其他需要校验的地方。在修改某个校验规则的时候,只需要编写或者该写少量的代码。
3、总结
策略模式定义了一系列算法,从概念上来说,所有的这些算法都是做相同的事情,只是实现不同,他可以以相同的方式调用所有的方法,减少了各种算法类与使用算法类之间的耦合。
从另外一个层面上来说,单独定义算法类,也方便了单元测试,因为可以通过自己的算法进行单独测试。
实践中,不仅可以封装算法,也可以用来封装几乎任何类型的规则,是要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑是要策略模式来处理各种变化。
从另外一个层面上来说,单独定义算法类,也方便了单元测试,因为可以通过自己的算法进行单独测试。
实践中,不仅可以封装算法,也可以用来封装几乎任何类型的规则,是要在分析过程中需要在不同时间应用不同的业务规则,就可以考虑是要策略模式来处理各种变化。
优点:
- 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句;
- 策略模式提供了对开放-封闭原则的完美支持,将算法进行封装,使得它们易于切换,易于理解和易于扩展;
- 策略模式的代码可以复用在代码的其他地方,从而避免许多重复的复制黏贴工作,也使得代码更简洁。
阅读全文
1 0
- 【JavaScript设计模式】行为型设计模式--策略模式
- 设计模式 - 行为型模式 - 策略模式
- 设计模式->行为型模式->策略模式
- 设计模式-行为-策略
- 设计模式--行为型--策略模式
- 设计模式14:策略模式【行为型】
- [设计模式-行为型]策略模式(Strategy)
- 设计模式-行为型之策略模式
- 行为型设计模式-策略模式
- java-行为型模式-策略设计模式
- 行为型的设计模式-策略模式
- 设计模式--行为模式--策略模式--Java
- 设计模式 行为模式之策略模式
- 【JavaScript设计模式】行为型设计模式--模板方法模式
- 【JavaScript设计模式】行为型设计模式--职责链模式
- 【JavaScript设计模式】行为型设计模式--发布-订阅模式
- java设计模式之行为型模式-策略模式
- 设计模式之行为型模式---策略模式
- Zabbix-3.04 添加自定义 监控MySQL
- 磁盘缓存
- hibernate写xml文件没有提示怎么办
- 对话框的几种实现方式
- android USB Accessory
- 【JavaScript设计模式】行为型设计模式--策略模式
- 4.4.C语言复杂表达式和指针高级应用
- SpringMVC-向jsp页面传递数据库读取到的值
- syslog的启用
- 输入框自动提示的实现
- linux常用命令之移动,拷贝,删除文件
- linux--yum
- Synchronized关键字解析
- [leetcode]397. Integer Replacement