javascript的策略模式(一)

原创
2016/05/17 17:54
阅读数 37

在程序设计中我们往往会遇到实现某一功能有多种方案可以选择。比如一个压缩算法,我们可以选择zip算法,也可以选择gzip算法。这些算法灵活多样,而且可以随意互相替换。

实例:按照不同等级计算奖金

var performanceS= function(salary){
   return salary*4;
}
var performanceA= function(salary){
   return salary*3;
}
var performanceB= function(salary){
   return salary*2;
}
varcalculateBonus = function(performanceLevel,salary){
   if(performanceLevel==”S”){
     return performanceS(salary);
   }
   if(performanceLevel==”A”){
     return performanceA(salary);
   }
   if(performanceLevel==”B”){
     return performanceB(salary);
   }
}
calculateBonus(‘A’,10000);

缺点:

l   if-else分支多,这些分支要覆盖所有的逻辑

l   calculateBonus函数缺乏弹性,如果增加了一种新的绩效等级C,或是把绩效S的奖金系数改为5,那么我们必须深入calculateBonus函数的内部实现,这违反开放—封闭原则

l   算法的复用性差,如果在程序的其他地方需要重用这些计算奖金的算法呢?我们只有复制和粘贴。

用策略模式修改

var strategies = {
 “S”:function(salary){
   return salary*4;
 },
 “A”:function(salary){
   return salary*4;
 },
 “B”:function(salary){
   return salary*4;
 }
};
var calculateBonus =function(level,salary){
  return strategies[level](salary);
}
console.log(calculateBonus(‘S’,20000)); //输出80000
console.log(calculateBonus(‘S’,10000)); //输出30000

 策略模式的目的就是将算法的使用与算法的实现分离开来。

因此一个策略模式的程序至少由两部分组成

第一个部分是一组策略类,它封装了具体的算法,并负责具体的计算过程。

第二个部分是环境类Context,Context接受客户请求,随后把请求委托给一个策略类。要做到这一点,说明Context中要维持对某个策略对象的引用

应用实例:表单验证。

<html>
<head>
<meta http-equiv="content-type" content="text/html;charset=utf-8">

<head>
<body>  
   <form action='' id='registerForm' method='post'>  
       请输入用户名:<input type='text' name='userName' /><br>  
       请输入密码:<input type='text' name = 'password' /> <br> 
       请输入手机号码:<input type='text' name = 'phoneNumber' />  <br>
		<input type='submit' value = '提交' />
  </form>  
  <script src="index.js"></script>
</body>  
</html>

index.js

//javascript

var strategies = {
	isNoEmpty: 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;
		}
	}

}


var Validator = function(){
	this._cache = [];
}

Validator.prototype.add = function(dom, rules){
	var self = this;
	for(var i=0; i<rules.length; i++){
		(function(rule){
			var strategyAry = rule.strategy.split(':');
			var errorMsg = rule.errorMsg;
			self._cache.push(function(){
				var strategy = strategyAry.shift();
				strategyAry.unshift(dom.value);
				strategyAry.push(errorMsg);
				return strategies[strategy].apply(dom, strategyAry);
			});
		})(rules[i])
	
	}

};

Validator.prototype.start = function(){
	for(var i=0, validatorFunc;validatorFunc = this._cache[i++];){
		var errorMsg = validatorFunc();
		if(errorMsg){
			return errorMsg;
		}
	
	}

}


var registerForm = document.getElementById('registerForm');
var validataFunc = function(){
	var validator = new Validator();
	console.log(validator);
	validator.add(registerForm.userName, [
			{  
				strategy:'isNoEmpty',  
				errorMsg:'用户名不能为空'  
			},
			{  
				strategy:'minLength:10',  
				errorMsg:'用户名长度不能小于10'  
			}
	
	]);
	validator.add(registerForm.password, [
			{  
				strategy:'minLength:6',  
				errorMsg:'密码长度不能小于6'  
			}
	
	]);
	validator.add(registerForm.phoneNumber, [
			{  
				strategy:'isMobile',
				errorMsg:'手机号码格式不正确'  
			}
	
	]);

	var errorMsg = validator.start();
	return errorMsg;

}


registerForm.onsubmit = function(){
	var errorMsg = validataFunc();
	if(errorMsg){
			alert(errorMsg);
			return false;
	}


}

 

展开阅读全文
打赏
2
0 收藏
分享
加载中
更多评论
打赏
0 评论
0 收藏
2
分享
返回顶部
顶部