【javascript】javasrcipt设计模式之策略模式
策略模式支持在运行时由使用者选择合适的算法,对于使用者而言不用关心背后的具体事项,而使用者自动根据当前程序执行的上下文和配置,从已有的算法列表中选择出合适的算法来处理当前任务。
1.要解决的问题
2.如何实现
3.在开源框架和类库中的使用
4.总结
要解决的问题
策略模式同样解决的是解耦的问题,目的是使调用的客户端与需要调用的算法解耦开来,保证算法的内部实现的更改不会影响到客户端的调用。当然这些算法往往需要封装为较为通用的。这样一来可以自由的从算法几种选取需要调用的合适的算法,就像搭积木一样,而算法也可以独立出来单测。
如何实现(应用场景之一表单验证)
对于一个表单,各个字段的输入值格式并不唯一,有的是数字,有的是电话号码。因而他们可能有各自都有的验证的要求。
策略模式是可复用的,比如多个字段可能都要求验证非空,这时,我们可以把场景的验证策略抽象为一个策略集合
使用者需要对表单数据进行校验时,只需要传入数据以及制定各个字段的验证策略,就可以给出相应的验证结果了,从而将表达你的处理和验证逻辑分离开来。
方法
validator.types = {
isNotEmpty: {
validate: function(value){
return value !== "";
},
message: "不得为空"
},
isNotEqualTo: {
validate: function(data, curField, compareField){
return data[curField] === data[compareField];
},
message: function(fieldText){
return "不得与" + fieldText + "相同,请重新输入";
}
},
isValidName: {
validate: function(value){
return (/^[\u4e00-\u9fa5]{2,4}$/).test(value);
},
message: "只能为2-4个字的汉字"
},
isValidIdentity: {
validate: function(value){
return (/^\d{6}(18|19|20)?\d{2}(0[1-9]|1[12])(0[1-9]|[12]\d|3[01])\d{3}(\d|X)$/i).test(value);
},
message: "不合法,请输入身份证上的18位身份证号"
},
isBirthEqualTo: {
validate: function(data, curField, compareField){
return data[curField].replace(/-/g, '') === data[compareField].substr(6, 8);
},
message: function(fieldText){
return "与" + fieldText + "中生日不一致,请修改";
}
},
isValidDate: {
validate: function(value){
var t = new Date(value),
paddingZero = function(value){
return value < 10 ? ('0' + value) : value;
},
transStr = [t.getFullYear(), paddingZero(t.getMonth() + 1), paddingZero(t.getDate())].join('-');
return transStr === value;
},
message: '格式不合法,请按"2008-01-01"格式输入日期'
},
isValidMobile: {
validate: function(value){
return (/^0?(13[0-9]|15[012356789]|18[02356789]|14[57])[0-9]{8}$/).test(value);
},
message: "格式不合法,请输入正确的手机号码"
},
isValidEmail: {
validate: function(value){
return (/^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$/).test(value);
},
message: "格式不合法,请输入正确的Email地址"
}
};
处理数据并放入方法
var validator = {
// 所有可用的校验
types: {},
// 错误信息
messages: [],
// 当前校验配置
config: {},
// 接口方法
validate: function(data){
var i, msg, item, validators, validatorItem, checker, result;
// 重置错误消息
this.messages = [] ;
// 遍历要校验的键值对数据
for(i in data){
console.log(i)
if(data.hasOwnProperty(i)){
// 获取校验项
item = this.config[i];
// 不存在校验项,不需要校验
if(!item){
continue;
}
// 遍历校验项
validators = item.validators;
for(var v = 0, len = validators.length; v < len; v++){
// 获取对应的校验模块
validatorItem = validators[v];
// 校验项为字符串,直接校验
if(typeof validatorItem == 'string'){
checker = this.types[validatorItem];
console.log(validatorItem,'字符串');
if(!checker){
throw {
name: "ValidationError",
message: "No handler to validate type " + validators[v]
};
}
result = checker.validate(data[i]);
console.log(checker,'字符串结果')
}else if(Array.isArray(validatorItem)){
console.log(validatorItem,'数组');
checker = this.types[validatorItem[0]];
if(!checker){
throw {
name: "ValidationError",
message: "No handler to validate type " + validators[v]
};
}
// 替换validatorItem第一个元素(validatorName)为data[i](当前校验项值)
console.log(validatorItem.slice(1),'截取');
console.log([data, i],'数组加上后面')
result = checker.validate.apply(this, [data, i].concat(validatorItem.slice(1)));
}else{
throw {
name: "ValidationError",
message: "No such validator *" + validatorItem + "* found."
};
}
// 校验不通过
if(!result){
// 校验器message类型可为string/function
var msgType = typeof checker.message;
if(msgType == 'string'){
msg = item.text + checker.message;
}else if(msgType == 'function'){
msg = item.text + checker.message.call(null, this.config[validatorItem[1]].text);
}
this.messages.push(msg);
}
}
}
}
return this.hasErrors();
},
hasErrors: function(){
return this.messages.length !== 0;
}
};
数据以及配置
var data = {
name: '王x',
gender: 1,
identity: '011110198806061234',
birthday: '1988-13-01',
mobile: '15800000000',
spareMobile: '13911111111',
email: 'abcdef.cn'
};
//校验配置
validator.config = {
name: {
text: '姓名',
validators: ['isNotEmpty', 'isValidName']
},
identity: {
text: '身份证号',
validators: ['isNotEmpty','isValidIdentity']
},
birthday: {
text: '生日',
validators: [['isBirthEqualTo','identity'],'isValidDate']
},
mobile: {
text: '手机号码',
validators: ['isValidMobile']
},
spareMobile: {
text: '备用手机号码',
validators: ['isValidMobile', ['isNotEqualTo', 'mobile']]
},
email: {
text: 'Email',
validators: ['isValidEmail']
}
};
调用方法
validator.validate(data);
if(validator.hasErrors()){
console.log(validator.messages.join('\n'));
}
总结:
策略模式对于有多种可提炼出较为通用的算法,并在不同的使用场景中可能会按需选择某一种或某几种策略完成对应的业务逻辑时比较有用。
所以如果当你的程序中设计到类似的一些场景,入业务逻辑涉及到分类和按需应用时,就可以考虑策略模式来实现算法和调用的解耦。
【javascript】javasrcipt设计模式之策略模式的更多相关文章
- JavaScript设计模式之策略模式(学习笔记)
在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...
- JavaScript设计模式之策略模式
所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...
- 设计模式:策略模式(Strategy)
定 义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...
- PHP设计模式之策略模式
前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...
- 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)
原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...
- 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查
原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...
- [design-patterns]设计模式之一策略模式
设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不 ...
- 设计模式入门,策略模式,c++代码实现
// test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...
- 设计模式之策略模式和状态模式(strategy pattern & state pattern)
本文来讲解一下两个结构比较相似的行为设计模式:策略模式和状态模式.两者单独的理解和学习都是比较直观简单的,但是实际使用的时候却并不好实践,算是易学难用的设计模式吧.这也是把两者放在一起介绍的原因,经过 ...
随机推荐
- 南昌网络赛 I. Max answer (单调栈 + 线段树)
https://nanti.jisuanke.com/t/38228 题意给你一个序列,对于每个连续子区间,有一个价值,等与这个区间和×区间最小值,求所有子区间的最大价值是多少. 分析:我们先用单调栈 ...
- 2018沈阳网络赛 - Ka Chang KD树暴力
题意:给你一棵树,n个点q次操作,操作1查询x子树深度为d的节点权值和,操作2查询子树x权值和 把每个点按(dfn,depth)的二维关系构造kd树,剩下的只需维护lazy标记即可 #include& ...
- (六)Audio子系统之AudioRecord.release
在上一篇文章<(五)Audio子系统之AudioRecord.stop>中已经介绍了AudioRecord如何暂停录制,接下来,继续分析AudioRecord方法中的release的实 ...
- dubbo和zookeeper的关系
转载前言:网络上很多教程没有描述zookeeper和dubbo到底是什么关系.分别扮演了什么角色等信息,都是说一些似是而非的话,这里终于找到一篇文章,比较生动地描述了注册中心和微服务框架之间的关系,以 ...
- Mac 10.12安装Git管理工具SourceTree
说明:Git的GUI工具应该是这款最好用. 下载: (链接: https://pan.baidu.com/s/1mhRr35Y 密码: vv67)
- android studio2.3.3 模拟器 Jni函数调用C++对象,lldb调试this指针和相关变量显示无效的原因
android studio2.3.3 的版本中 Jni函数调用C++对象,对象调用相关的成员函数, lldb调试,变量跟踪窗口,this指针和相关变量显示无效的原因,但这些参数实际是有效的,只是de ...
- 【ZooKeeper】单机伪集群搭建(适用于mac)
1.配置 .zookeeper下载地址:http://apache.mirrors.lucidnetworks.net/zookeeper/ 可以选择需要的版本,我下载的是zookeeper-3.4. ...
- springboot-22-自定义starter
先说下springboot的运行原理 springboot最主要的配置 是 @SpringBootApplication 然后这里面 @EnableAutoCOnfiguration 最为重要, 继续 ...
- [作业] Python入门基础---九九乘法表
1.while 循环 : x = 1 while x < 10: y = 1 while y <=x: print('%d*%d=%2d' % (y,x,x*y),end = '\t') ...
- SSH安全登陆原理:密码登陆与公钥登陆
SSH全称(Secure SHell)是一种以安全性闻名的应用层网络通信协议,用于计算机间的安全通信,是目前比较成熟的远程登陆解决方案. 它提供两种方法登陆: 1.密码登陆 2.公钥登陆 密码 ...