策略模式定义一系列算法和规则,将它们一个个封装起来,并且使它们可以互相替换。策略模式最重要的是策略对象,还有执行策略对象的上下文。
如下的代码:strategies是策略对象(封装了各种情况);calculateBonus是Context(执行的上下文);并没有计算的能力,而是把这个职责委托给了某个策略对象,每个策略对象负责的算法已经封装在对象的内部了.
var strategies={
"S":function(salary){
return salary*4;
},
"A":function(salary){
return salary*3
}
};
// Context
var calculateBonus=function(level,salary){
return strategies[level](salary);
}
使用策略模式可以封装一些算法,缓动动画的算法之类;使用策略模式也可以封装一系列的"业务规则",(只要这些业务规则指向的目标一致,这些业务规则是平行的,并且可以被替换使用),就可以用策略模式来封装。
策略模式封装表单验证:
var strategies={
isNonEmpty:function(value,errorMsg){
if(value===''){
return errorMsg;
}
},
minLength:function(value,length,errorMsg){
if(value.length<length){
return errorMsg
}
},
isMoblie:function(value,errorMsg){
if(!/^1[3|5|8][0-9]{9}$/.test(value)){
return errorMsg;
}
}
}
// Validator类在这里作为Context,负责接收用户的请求并委托给strategy对象.在给出Validator类之前,有必要提前了解用户是如何向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); //指向每一个dom.
})
}
Validator.prototype.start=function(){
for(var i=0,validataFunc;validataFunc=this.cache[i++];){
var msg=validataFunc(); //调用函数
if(msg){
return msg;
}
}
}
var validataFunc=function(){
var validator=new Validator();
validator.add(reg.userName,'isNonEmpty','用户名不为空');
validator.add(reg.userName,[{strategy:'isNonEmpty',errMsg:'用户名不为空'},{strategy:'minLength',errMsg:'密码长度不能少于'},]);
validator.add(reg.pass,'minLength:6','密码长度不能少于6位');
validator.add(reg.ph,'isMoblie','手机号码格式不正确');
var errorMsg=validator.start();
return errorMsg;
}
var reg=document.getElementById('reg');
reg.onsubmit=function(){
var errorMsg=validataFunc();
if(errorMsg){
alert(errorMsg);
return false;
}
}
策略模式:各个策略类之间是平等又平行的,它们之间没有任何联系,所以客户必须熟知这些策略类的作用,以便客户可以随时主动切换算法。