策略模式支持在运行时由使用者选择合适的算法,对于使用者而言不用关心背后的具体事项,而使用者自动根据当前程序执行的上下文和配置,从已有的算法列表中选择出合适的算法来处理当前任务。

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设计模式之策略模式的更多相关文章

  1. JavaScript设计模式之策略模式(学习笔记)

    在网上搜索“为什么MVC不是一种设计模式呢?”其中有解答:MVC其实是三个经典设计模式的演变:观察者模式(Observer).策略模式(Strategy).组合模式(Composite).所以我今天选 ...

  2. JavaScript设计模式之策略模式

    所谓"条条道路通罗马",在现实中,为达到某种目的往往不是只有一种方法.比如挣钱养家:可以做点小生意,可以打分工,甚至还可以是偷.抢.赌等等各种手段.在程序语言设计中,也会遇到这种类 ...

  3. 设计模式:策略模式(Strategy)

    定   义:它定义了算法家族,分别封装起来,让它们之间可以互相替换,此模式让算法的变化, 不会影响到使用算法的客户. 示例:商场收银系统,实现正常收费.满300返100.打8折.......等不同收费 ...

  4. PHP设计模式之策略模式

    前提: 在软件开发中也常常遇到类似的情况,实现某一个功能有多种算法或者策略,我们可以根据环境或者条件的不同选择不同的算法或者策略来完成该功能.如查 找.排序等,一种常用的方法是硬编码(Hard Cod ...

  5. 乐在其中设计模式(C#) - 策略模式(Strategy Pattern)

    原文:乐在其中设计模式(C#) - 策略模式(Strategy Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 策略模式(Strategy Pattern) 作者:webabc ...

  6. 【设计模式】【应用】使用模板方法设计模式、策略模式 处理DAO中的增删改查

    原文:使用模板方法设计模式.策略模式 处理DAO中的增删改查 关于模板模式和策略模式参考前面的文章. 分析 在dao中,我们经常要做增删改查操作,如果每个对每个业务对象的操作都写一遍,代码量非常庞大. ...

  7. [design-patterns]设计模式之一策略模式

    设计模式 从今天开始开启设计模式专栏,我会系统的分析和总结每一个设计模式以及应用场景.那么首先,什么是设计模式呢,作为一个软件开发人员,程序人人都会写,但是写出一款逻辑清晰,扩展性强,可维护的程序就不 ...

  8. 设计模式入门,策略模式,c++代码实现

    // test01.cpp : Defines the entry point for the console application.////第一章,设计模式入门,策略模式#include &quo ...

  9. 设计模式之策略模式和状态模式(strategy pattern & state pattern)

    本文来讲解一下两个结构比较相似的行为设计模式:策略模式和状态模式.两者单独的理解和学习都是比较直观简单的,但是实际使用的时候却并不好实践,算是易学难用的设计模式吧.这也是把两者放在一起介绍的原因,经过 ...

随机推荐

  1. 4、2支持向量机SVM算法实践

    支持向量机SVM算法实践 利用Python构建一个完整的SVM分类器,包含SVM分类器的训练和利用SVM分类器对未知数据的分类, 一.训练SVM模型 首先构建SVM模型相关的类 class SVM: ...

  2. jenkins发送测试报告邮件

     1.安装插件 Email Extension Plugin 2.设置Extended E-mail Notification a."系统管理"--“系统设置”.配置Extende ...

  3. TP5 隐藏入口文件 index.php

    找到public下的.htaccess <IfModule mod_rewrite.c> Options +FollowSymlinks -Multiviews RewriteEngine ...

  4. loj 6433 「PKUSC2018」最大前缀和 题解【DP】【枚举】【二进制】【排列组合】

    这是个什么集合DP啊- 想过枚举断点但是不会处理接下来的问题了- 我好菜啊 题目描述 小 C 是一个算法竞赛爱好者,有一天小 C 遇到了一个非常难的问题:求一个序列的最大子段和. 但是小 C 并不会做 ...

  5. 开源.net 混淆器ConfuserEx介绍 [转]

    今天给大家介绍一个开源.net混淆器——ConfuserEx http://yck1509.github.io/ConfuserEx/ 由于项目中要用到.net 混淆器,网上搜寻了很多款,比如Dotf ...

  6. 【系统】Ubuntu和win7双系统更改系统引导菜单

    1. 下载EasyBCD 2. 编辑菜单选项以及重写MBR

  7. java反射机制_读取properties

    代码: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * 反射特点: ...

  8. MongoDB日志文件过大

    MongoDB日志文件过大 MongoDB启动的时候指定了--logpath为一个日志文件.随着时间此文件会变得越来越大,达到好几个G. 因为不想让MongoDB进程重新启动,所以不能停止进程删除此文 ...

  9. java String 提供的方法

    String类的判断功能: * boolean equals(Object obj):比较字符串的内容是否相同,区分大小写 * boolean equalsIgnoreCase(String str) ...

  10. Java测试各种数据库连接(用Connection类)

    源代码: package cn.finedo.fdcollect_service.util; import java.sql.Connection; import org.apache.logging ...