策略模式定义: 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换;
2 策略模式
策略模式定义: 定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换;
2.1 策略模式
策略模式的目的就是将算法的使用与算法的实现分离开来,将不变的部分和变化的部分隔开是每个设计模式的主题;
一个基于策略模式的程序至少由两部分组成。第一个部分是一组策略类,策略类封装了具体的算法,并负责具体的计算过程。 第二个部分是环境类 Context, Context 接受客户的请求,随后把请求委托给某一个策略类。要做到这点,说明 Context 中要维持对某个策略对象的引用;
实例:积分模式(基础分乘上对于的等级倍数)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| var calculateBonus = function( level, base ){ if ( level === 'S' ){ return base * 4; } if ( level === 'A' ){ return base * 3; } }; calculateBonus( 'B', 10 ); calculateBonus( 'S', 5 );
var performanceS = function(){}; performanceS.prototype.calculate = function( base ){ return base * 4; }; var performanceA = function(){}; performanceA.prototype.calculate = function( base ){ return base * 3; };
var Bonus = function(){ this.base = null; this.strategy = null; }; Bonus.prototype.setSalary = function( base ){ this.base = base; }; Bonus.prototype.setStrategy = function( strategy ){ this.strategy = strategy; }; Bonus.prototype.getBonus = function(){ return this.strategy.calculate( this.base ); };
|
2.2 JavaScript 版本的策略模式
在 JavaScript 语言中,函数也是对象,所以更简单和直接的做法是把 strategy 直接定义为函数:
1 2 3 4 5 6 7 8 9
| var strategies = { "S": function( base ){ return base * 4; }, "A": function( base ){ return base * 3; }, }; var calculateBonus = function( level, base ){ return strategies[ level ]( base ); }; console.log( calculateBonus( 'S', 10 ) ); console.log( calculateBonus( 'A', 5 ) );
|
2.3 策略模式实现表单校验
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54
| 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; } } };
var Validator = function(){ this.cache = []; }; Validator.prototype.add = function( dom, rule, errorMsg ){ var ary = rule.split( ':' ); this.cache.push(function(){ var strategy = ary.shift(); ary.unshift( dom.value ); ary.push( errorMsg ); return strategies[ strategy ].apply( dom, ary ); }); }; Validator.prototype.start = function(){ for ( var i = 0, validatorFunc; validatorFunc = this.cache[ i++ ]; ){ var msg = validatorFunc(); if ( msg ){ return msg; } } };
var validataFunc = function(){ var validator = new Validator(); validator.add( registerForm.userName, 'isNonEmpty', '用户名不能为空' ); validator.add( registerForm.password, 'minLength:6', '密码长度不能少于 6 位' ); validator.add( registerForm.phoneNumber, 'isMobile', '手机号码格式不正确' ); var errorMsg = validator.start(); return errorMsg; }
var registerForm = document.getElementById( 'registerForm' ); registerForm.onsubmit = function(){ var errorMsg = validataFunc(); if ( errorMsg ){ alert ( errorMsg ); return false; } };
|
2.4 策略模式的优缺点
策略模式的优点:
- 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重条件选择语句;
- 策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy 中,使得它们易于切换,易于理解,易于扩展;
- 策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复的复制粘贴工作;
- 在策略模式中利用组合和委托来让 Context 拥有执行算法的能力,这也是继承的一种更轻便的替代方案;
策略模式的缺点:
- 使用策略模式会在程序中增加许多策略类或者策略对象,但实际上这比把它们负责的逻辑堆砌在 Context 中要好;
- 使用策略模式,必须了解所有的 strategy,必须了解各个 strategy 之间的不同点,这样才能选择一个合适的 strategy ;由于 strategy 要向客户暴露它的所有实现,这是违反最少知识原则;
2.5 一等函数对象与策略模式
之前的策略模式示例中,既有模拟传统面向对象语言的版本,也有针对 JavaScript 语言的特有实现。在以类为中心的传统面向对象语言中,不同的算法或者行为被封装在各个策略类中, Context 将请求委托给这些策略对象,这些策略对象会根据请求返回不同的执行结果,这样便能表现出对象的多态性;
在 JavaScript 中,除了使用类来封装算法和行为之外,直接使用函数也是一种选择。这些“算法”可以被封装到函数中并且四处传递,也就是常说的“高阶函数”。实际上在 JavaScript 这种将函数作为一等对象的语言里,策略模式已经融入到了语言本身当中,我们经常用高阶函数来封装不同的行为,并且把它传递到另一个函数中。当我们对这些函数发出“调用”的消息时,不同的函数会返回不同的执行结果;
1 2 3 4 5 6 7
| var S = function( salary ){ return salary * 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, 10 );
|
2.6 策略模式小结
本小节既有接近传统面向对象语言的策略模式实现,也有更适合 JavaScript 语言的策略模式版本。在 JavaScript 语言的策略模式中,策略类往往被函数所代替,这时策略模式就成为一种“隐形”的模式。
系列链接
- JavaScript 设计模式基础知识
- JavaScript 设计模式(一)单例模式
- JavaScript 设计模式(二)策略模式
- JavaScript 设计模式(三)代理模式
- JavaScript 设计模式(四)迭代器模式
- JavaScript 设计模式(五)发布订阅模式
- JavaScript 设计模式(六)命令模式
- JavaScript 设计模式(七)组合模式
- JavaScript 设计模式(八)模板方法模式
- JavaScript 设计模式(九)享元模式
- JavaScript 设计模式(十)职责链模式
- JavaScript 设计模式(十一)中介者模式
- JavaScript 设计模式(十二)装饰者模式
- JavaScript 设计模式(十三)状态模式
- JavaScript 设计模式(十四)适配器模式
- JavaScript 设计模式(下)设计原则
- JavaScript 设计模式练习代码