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 ); // 输出:40000calculateBonus( "S", 6000 ); // 输出:24000可以发现,这段代码十分简单,但是存在着显而易见的缺点。var performanceS = function( salary ){ return salary * 4;};var performanceA = function( salary ){ return salary * 3;};var performanceB = function( salary ){ return salary * 2;};var calculateBonus = function( performanceLevel, salary ){ if ( performanceLevel === "S" ){ return performanceS( salary ); } if ( performanceLevel === "A" ){ return performanceA( salary ); } if ( performanceLevel === "B" ){ return performanceB( salary ); }};calculateBonus( "A" , 10000 ); // 输出:30000目前,我们的程序得到了一定的改善,但这种改善非常有限,我们依然没有解决最重要的问题:calculateBonus函数有可能越来越庞大,而且在系统变化的时候缺乏弹性。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 ); //把计算奖金的操作委托给对应的策略对象};在完成最终的代码之前,我们再来回顾一下策略模式的思想: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实现的策略模式。
var strategies = { "S": function( salary ){ return salary * 4; }, "A": function( salary ){ return salary * 3; }, "B": function( salary ){ return salary * 2; }}; 同样,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 ) ); // 输出: 80000console.log( calculateBonus( "A", 10000 ) ); // 输出: 300003、实例再讲解$( div ).animate( {"left: 200px"}, 1000, "linear" ); //匀速运动$( div ).animate( {"left: 200px"}, 1000, "cubic" ); //三次方的缓动这2句代码都是让div在1000ms内往右移动200个像素. linear(匀速)和cubic(三次方缓动)就是一种策略模式的封装.
比如姓名框里面, 需要验证非空,敏感词,字符过长这几种情况。 当然是可以写3个if else来解决,不过这样写代码的扩展性和维护性可想而知。如果表单里面的元素多一点,需要校验的情况多一点,加起来写上百个if else也不是没有可能。
所以更好的做法是把每种验证规则都用策略模式单独的封装起来。需要哪种验证的时候只需要提供这个策略的名字。就像这样:
nameInput.addValidata({ notNull: true, dirtyWords: true, maxLength: 30})而notNull,maxLength等方法只需要统一的返回true或者false,来表示是否通过了验证。validataList = { notNull: function( value ){ return value !== ""; }, maxLength: function( value, maxLen ){ return value.length() > maxLen; }}可以看到,各种验证规则很容易被修改和相互替换。如果某天产品经理建议字符过长的限制改成60个字符。那只需要0.5秒完成这次工作。