策略模式的定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
使用策略模式实现计算奖金
奖金的计算方式:绩效为S的人奖金为工资的4倍,绩效为A的奖金为工资的3倍,绩效为B的奖金为工资的2倍。
//每种绩效的计算规则封装到对应的策略类
var performanceS = function(){};
performanceS.prototype.calculate = function(salary){
return salary * 4;
}
var performanceA = function(){};
performanceA.prototype.calculate = function(salary){
return salary * 3;
}
var performanceB = function(){};
performanceB.prototype.calculate = function(salary){
return salary * 2;
}
//定义奖金类Bonus:
var Bonus = function(){
this.salary = null;
this.strategy = null;
};
Bonus.prototype.setSalary = function(salary){
this.salary = salary;
}
Bonus.prototype.setStrategy = function(strategy){
this.strategy = strategy
}
Bonus.prototype.getBonus = function(){
return this.strategy.calculate(this.salary);
}
对于上面的解释:定义一系列的算法,把它们封装成策略类,算法被封装在策略类内部的方法里,在客户对Context发起请求的时候,Context总是把请求委托给这些策略对象中的某一个进行计算。
var bonus = new Bonus();
bonus.setSalary(10000);
bonus.setStrategy(new perFormanceS());
console.log(bonus.getBonus()); // 40000
bonus.setStrategy(new perFormanceA());
console.log(bonus.getBonus()); //30000
我们使用策略模式重构了计算奖金的代码,可以看到重构之后代码变得比较清晰,各个类的职责更加鲜明。但这代码是基于传统面向对象语言的模仿,下面我将了解用javaScript实现策略模式。
Javascript版本的策略模式
var strategies = {
"S": function(salary){
return salary * 4;
},
"A": function(salary){
return salary * 3;
},
"B": function(salary){
return salary * 2;
}
}
var calculateBonus = function(level,salary){
return strategies[level](salary);
}
console.log(calculateBonus('S',20000)); // 80000
console.log(calculateBonus('A',10000)); // 30000
更广义的”算法“
从定义上看,策略模式就是用来封装算法的,但是如果把策略模式仅仅用来封装算法有点大材小用。在实际开发中,我们通常会把算法的含义扩散开来,使策略模式也可以封装一系列的”业务规则“。只要这些业务规则指向的目标一致,并且可以被替换使用,我们就可以用策略模式来封装它们。
用策略模式实现表单校验
编辑一个注册的页面,在点击注册按钮之前,有如下几条校验规则:
- 用户名不能为空。
- 密码长度不能少于6位。
- 手机号必须符合格式。
<html lang="en">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<form action='http://xxx.com/register' id="registerForm" method="post">
请输入用户名:<input type="text" name="userName"/>
请输入密码:<input type="text" name="password"/>
请输入手机号码:<input type="text" name="phoneNumber/>
<button>提交</button>
</form>
</body>
<script>
/********策略类*****/
var strategies = {
isNonEmpty: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;
}
}
}i++
/*************Validator类************/
var Validator = function(){
this.cache = [];
}
Validator.prototype.add = function(dom,rules){
var self = this;
for(var i = 0; rule;rule = rules[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);
});
})(rule)
}
};
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();
validator.add(registerForm.userName,[{strategy:'isNonEmpty',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;
}
}
</script>
</html>
策略模式的优缺点
策略模式的优点:
- 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句。
- 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的strategy中,使得他们易于切换,易于理解,易于扩展。
- 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
- 在策略模式中利用组合和委托来让Context拥有执行算法的能力,这也是继承的一种更轻便的代替方案。 策略模式的缺点:
- 需要增加许多策略类或者策略对象
- 使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同才能选择一个适合的strategy。