一、策略模式定义:

定义一些列的算法/规则,将它们封装起来,使得它们可以互相替换/组合使用。其目的在于将算法/规则封装起来,将算法/规则的使用与实现分离出来。

通过策略模式,可以减少算法计算过程中大量的if-else分支,并提高复用性。

一个策略模式的程序至少由两部分组成,一个是一组策略类,策略类封装了具体算法,并负责具体的实现过程;第二个部分是环境类context,context接受客户的请求,随后将请求委托给具体的某一个策略类。context中需要有一个变量来保存对对象的引用。

二、java中的策略模式:

考虑以下应用场景,大部分公司都会根据绩效发放年终奖,假设说如果绩效为A的话,年终奖发放5倍月薪;如果绩效为B的话,年终奖发放4倍月薪。按照一般的思路,计算函数中可能包含如下的分支语句,if (绩效为A) else if(绩效为B){};如果新增了一个C绩效,则需要进入计算函数的内部进行修改,因此考虑将算法的实现与算法的使用相分离。

为了实现多态,需要定义对应的接口或者抽象类:

package com.bobo.shejimoshi;

public abstract class Performance {

    public abstract int calBonus(int salary);

}

绩效A类:

package com.bobo.shejimoshi;

public class PerformanceA extends Performance{

    @Override
public int calBonus(int salary) {
// TODO Auto-generated method stub
return salary*;
}
}

绩效B类:

package com.bobo.shejimoshi;

public class PerformanceB extends Performance{

    @Override
public int calBonus(int salary) {
// TODO Auto-generated method stub
return salary*;
}
}

实现context类:

package com.bobo.shejimoshi;

public class Bonus {
private Performance perfo;
private int salary; public void setPerfo(Performance perfo) {
this.perfo = perfo;
} public void setSalary(int salary) {
this.salary = salary;
} public int getBonus(int salary){
return this.perfo.calBonus(salary);
}
}

调用方法如下:

package com.bobo.shejimoshi;

public class Test {

    public static void main(String[] args) {
Bonus bonus = new Bonus();
bonus.setPerfo(new PerformanceA());
System.out.println(bonus.getBonus());//输出4000 bonus.setPerfo(new PerformanceB());
System.out.println(bonus.getBonus());//输出5000
} }

三、javascript中的策略模式

在javascript中,函数也是对象,因此完全不必要使用策略类,将其直接定义为函数即可。对策略的引用可以像java中通过context类的一个属性来保存其引用,可以通过函数参数来进行传递。

    //策略模式

    //策略实现
var strategies={
'S':function(salary){
return salary*;
},
'A':function(salary){
return salary*;
},
'B':function(salary){
return salary*;
}
}; //context实现
var calBonus=function(leval,salary){
return strategies[leval].call(this,salary);
}; console.log(calBonus('S',));
console.log(calBonus('A',));

三、案例

1)jquery中的动画类,其各种缓动动画,也是策略模式的具体实现;

2)如果认为策略模式就是用来封装算法的,那未免太狭隘了,事实上,广义的算法也可以是一系列的“业务规则”,只要这些业务规则指向的目标一致,就可以被替换,甚至可以被组合使用。如下面封装的一个表单验证插件。

//使用策略模式来实现表单验证
var strategies = {
'isNonEmpty': function(value, errorMsg) {
if (value == '') {
return errorMsg;
}
},
'minLength': function(value, length, errorMsg) {
if (value.length < length) {
return errorMsg;
}
},
}; function Validate() {
this.cache = [];
}
Validate.prototype.add = function(dom, rules) {
var self = this;
for (var i = ; i < rules.length; i++) {
var curRule = rules[i];
(function(curRule) {
var argsAry = curRule['strategy'].split(':');
var errorMsg = curRule['errorMsg'];
self.cache.push(function() {
var strategy = argsAry.shift();
argsAry.unshift(dom.value);
argsAry.push(errorMsg);
return strategies[strategy].apply(dom, argsAry);
});
})(curRule);
}
};
Validate.prototype.start = function() {
for (var i = ; i < this.cache.length; i++) {
var func = this.cache[i];
var errorMsg = func();
if (errorMsg) {
return errorMsg;
}
}
};
var testForm = document.getElementById("testForm"); function validateForm() {
var validate = new Validate();
validate.add(testForm.username, [{ 'strategy': 'isNonEmpty', 'errorMsg': '该字段不能为空!' }]);
validate.add(testForm.password, [{ 'strategy': 'minLength:3', 'errorMsg': '输入长度不能小于3' }]);
console.log(validate.cache);
var errorMsg = validate.start();
return errorMsg;
}
testForm.onsubmit = function() {
var errorMsg = validateForm();
if (errorMsg) {
console.log(errorMsg);
return false;
}
};

如果采用《你不知道的javascript》中推崇的基于委托的写法,那么实现的代码如下:

//基于委托的表单验证组件的实现
//在编写组件之前,首先了解用户是如何使用组件的,总的来说,有两个API
//.add(registerForm.password,[{strategy:'minLength:6',errorMsg:'长度不能小于6'},{strategy:'isNonEmpty',errorMsg:'输入不能为空'}],'长度不能小于6位');添加校验规则
//.start()启动校验,返回错误信息 var strategies={
isNonEmpty:function(value,errorMsg){
console.log(arguments);
if(value==''){
return errorMsg;
}
},
minLength:function(value,length,errorMsg){
if(value.length<length){
return errorMsg;
}
},
isMobile:function(value,errorMsg){
if(!/^[||][-]{}/.test(value)){
return errorMsg;
}
}
};
var validator={
//不是函数,内部不能定义变量
//var cache=[],
init:function(){
this.cache=[];
},
add:function(elem,rules){
var i,len,self=this;
for(i=,len=rules.length;i<len;i++){
(function(i){
self.cache.push(function(){
//这是个闭包
var curRule=rules[i],
strategyAry=curRule.strategy.split(':'),
errorMsg=curRule.errorMsg,
strategy=strategyAry.shift();
strategyAry.push(errorMsg);
strategyAry.unshift(elem.value);
//console.log(strategy);
return strategies[strategy].apply(elem,strategyAry);
});
})(i); }
},
start:function(){
var i,len,errorMsg;
for(i=,len=this.cache.length;i<len;i++){
if((errorMsg=this.cache[i]())!==undefined){
return errorMsg;
}
}
} }; //测试
var form=document.forms['login']; var myValid=Object.create(validator);
myValid.init();
myValid.add(form.name,[{strategy:'isNonEmpty',errorMsg:'字段不能为空'},{strategy:'minLength:3',errorMsg:'长度不能小于3'}]);
console.log(myValid.start());

最新文章

  1. [百度网盘]Xamarin for Visual Studio 3.7.165 Preview 最新版-介绍
  2. 10月27日PHP加载类、设计模式(单例模式和工厂模式)、面向对象的六大原则
  3. Effective C++ -----条款54:让自己熟悉包括TR1在内的标准程序库
  4. android开发——学习总结20131204
  5. 如何在安装程序中判断操作系统是否是64位 inno
  6. 请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串&quot;+100&quot;,&quot;5e2&quot;,&quot;-123&quot;,&quot;3.1416&quot;和&quot;-1E-16&quot;都表示数值。 但是&quot;12e&quot;,&quot;1a3.14&quot;,&quot;1.2.3&quot;,&quot;+-5&quot;和&quot;12e+4.3&quot;都不是。
  7. Python模块包中__init__.py文件的作用
  8. PHP 新建动态类的代码
  9. struts2的action的知识点和利用action向页面注入值的操作
  10. C#界面设计疑问2:panel摆放问题
  11. python第二步,类对象部分
  12. window maven批量删除.lastUpdated文件
  13. 【树链剖分】洛谷P3379 树链剖分求LCA
  14. MIT-线性代数笔记(1-6)
  15. C# 获取当前屏幕DPI
  16. CentOS 7 最小安装网络配置
  17. flashfxp 数据socket错误 连接已超时 filezilla
  18. python学习Day1 计算机原理编程思维
  19. centos7切换gnome3桌面与gnome经典桌面
  20. Druid数据源对数据库访问密码加密好麻烦

热门文章

  1. QQ、淘宝、阿里旺旺在线网页链接代码及详解 很实用
  2. 在Windows下部署安装hexo
  3. Smart ECM数据发布假数据测试工作。
  4. 免费手机号码归属地API查询接口和PHP使用实例分享
  5. DataSet key points
  6. [转]为何TCP/IP协议栈设计成沙漏型的
  7. Java中的定时调度
  8. log4j常用配置以及日志文件保存位置
  9. Oracle存储过程java 调用
  10. Ubuntu 14.04 在桌面上双击运行shell 脚本文件