策略模式的定义:定义一系列的算法,把它们一个个封装起来,并且使它们可以互相替换。
一个基于策略模式的程序至少由两部分组成:
- 第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。
- 第二个部分是环境类Context,Context接受客户的请求,随后把请求委托给某个策略类。
如果不使用策略模式来实现多态性,将会存在以下缺陷:
- 功能函数比较庞大,包含大量if-else语句,这些语句需要覆盖所有的逻辑分支。
- 函数缺乏弹性,如果增加了一种新分支,或者修改一条分支的算法,我们必须深入函数的内部实现。这违反开放-封闭原则。
- 算法的复用性差,如果在程序其他地方需要重用这些分支算法,只能选择复制粘贴。
使用策略模式实现表单校验
HTML部分
<form action="http://xxx.com/register" method="post" id="registerForm">
请输入用户名:<input type="text" name="username" />
请输入密码:<input type="password" name="password" />
请输入手机号码:<input type="text" name="phoneNumber" />
<input type="submit" value="提交"/>
</form>
策略对象
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类
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 strateAry = rule.strategy.split(':'); //策略方法与方法参数使用 : 分隔,例如:minLength:6
var errorMsg = rule.errorMsg;
self.cache.push(function(){
var strategy = strateAry.shift();
strateAry.unshift( dom.value );
strateAry.push( errorMsg );
return strategies[ strategy ].apply( dom, strateAry );
});
})( 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;
}
}
策略模式的优缺点
优点
- 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件语句。
- 策略模式提供了对开放-封闭原则的完美支持,将算法封装在独立的strategy中,使得它们易于切换,易于理解,易于扩展。
- 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作。
- 在策略模式中利用组合和委托来让Context拥有执行算法的能力,这也是继承的一种更轻便的替代方案。
缺点
- 使用策略模式会在程序中增加许多策略类或者策略对象,但实际上这比它们负责的逻辑堆砌在Context中要好。
- 其次,要使用策略模式,必须了解所有的strategy,必须了解各个strategy之间的不同点,这样才能选择一个合适的strategy。这必须向调用者暴露它的所有实现,这违反最少知识原则。
策略模式的另一简易表现
var S = function( salary ){
return safary * 4;
};
var A = function( salary ){
return salary * 3;
};
var B = function( salary ){
return salary * 2;
}
var calculateBonus = function( func, salary ){
return func( salary );
}
calculateBonus( S, 10000 ); //输出:40000
网友评论