介绍
- 策略模式的定义是:定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。
- 在程序设计中,我们也常常遇到类似的情况,要实现某一个功能有多种方案可以选择。
- 将不变的部分和变化的部分隔开是每个设计模式的主题,策略模式也不例外,策略模式的目的就是将算法的使用与算法的实现分离开来。
正文
1.使用策略模式计算奖金
- 原始用if来判断,有以下缺点
(1)calculateBonus 函数比较庞大,包含了很多 if-else 语句。
(2)函数缺乏弹性,如果增加了一种新的绩效等级 C,或者想把绩效 S 的奖金系数改为 5,那我们必须深入 calculateBonus 函数的内部实现,这是违反开放封闭原则的。
(3)算法的复用性差,如果在程序的其他地方需要重用这些计算奖金的算法呢?我们的选择只有复制和粘贴。
因此,我们需要重构这段代码。
var calculateBonus = function( performanceLevel, salary ){
if ( performanceLevel === 'S' ){
return salary * 4;
}
if ( performanceLevel === 'A' ){
return salary * 3;
}
if ( performanceLevel === 'B' ){
return salary * 2;
}
};
calculateBonus( 'B', 20000 ); // 输出:40000
calculateBonus( 'S', 6000 ); // 输出:24000
- 实际上在 JavaScript 语言中,函数也是对象,所以更简单和直接的做法是把 strategy直接定义为函数, 同样,Context 也没有必要必须用 Bonus 类来表示,我们依然用 calculateBonus 函数充当Context来接受用户的请求。经过改造,代码的结构变得更加简洁:
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
2.使用策略模式进行表单校验
- 表单校验的第一个版本,缺点和上面一样
<html>
<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>
<script>
var registerForm = document.getElementById( 'registerForm' );
registerForm.onsubmit = function(){
if ( registerForm.userName.value === '' ){
alert ( '用户名不能为空' );
return false;
}
if ( registerForm.password.value.length < 6 ){
alert ( '密码长度不能少于6 位' );
return false;
}
if ( !/(^1[3|5|8][0-9]{9}$)/.test( registerForm.phoneNumber.value ) ){
alert ( '手机号码格式不正确' );
return false;
}
}
</script>
</body>
</html>
- 用策略模式重构表单校验,下面我们将用策略模式来重构表单校验的代码,很显然第一步我们要把这些校验逻辑都封装成策略对象:
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;
}
}
};
接下来我们准备实现 Validator 类。 Validator 类在这里作为 Context,负责接收用户的请求并委托给 strategy 对象。在给出 Validator 类的代码之前,有必要提前了解用户是如何向 Validator类发送请求的,这有助于我们知道如何去编写 Validator 类的代码。代码如下:
/***********************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;
}
}
};