[TOC] >[success] # 什么是策略模式(菜鸟教程中策略模式总结) ~~~ 1.定义一系列的算法,把它们一个个封装起来,并且使它们可以相互替换。 2.策略模式由两部分构成:一部分是封装不同策略的策略组,另一部分是 Context。 通过组合和委托来让 Context 拥有执行策略的能力,从而实现可复用、可扩展和可维护, 并且避免大量复制粘贴的工作。 3.主要解决:在有多种算法相似的情况下,使用 if...else 所带来的复杂和难以维护。 何时使用:一个系统有许多许多类,而区分它们的只是他们直接的行为。 如何解决:将这些算法封装成一个一个的类,任意地替换。 关键代码:实现同一个接口。(静态有类型检查为了可以任意替换因此需要接口,但js和他们不一样,如果ts另当别论) ~~~ >[danger] ##### 使用场景 ~~~ 1、如果在一个系统里面有许多类,它们之间的区别仅在于它们的'行为',那么使用策略模式可以动态地让一个对象在许多行为中选择一种行为。 2、一个系统需要动态地在几种算法中选择一种。 3、如果一个对象有很多的行为,如果不用恰当的模式,这些行为就只好使用多重的条件选择语句来实现。 ~~~ >[danger] ##### 优缺点 * 优点 ~~~ 1、算法可以自由切换。 2、避免使用多重条件判断。 3、扩展性良好。 ~~~ * 缺点 ~~~ 1、策略类会增多。 2、所有策略类都需要对外暴露。 ~~~ >[danger] ##### 注意点 ~~~ 1.如果一个系统的策略多于四个,就需要考虑使用混合模式,解决策略类膨胀的问题 ~~~ >[success] # 前端的策略模式 ~~~ 1.刚才的策略模式大部分针对后台来说的,但是如果想实现策略模式你需要,其实就是两部分 就上面说的第一个部分'封装不同策略的策略组'可以理解成多个if判断中的内容,'Context'执行 这些策略的调用 ~~~ >[danger] ##### 举个例子 ~~~ 1.公司要发奖金,根据不同等级奖金比例也是不同,为了判断每一个人应该根据等级和等级所对应的 倍数得到的奖金,写出下面的代码 2.下面的代码确定是什么大量的if判断不好维护,如果等级对应的倍数有所更改我们需要去改'calculateBonus ' ,对应代码中的分支逻辑,最可怕的是'算法复用性',如果其他地方需要用到这些计算公式某些条数,你能做的 只有复制粘贴 ~~~ ~~~ var calculateBonus = function (performanceLevel, salary) { if(performanceLevel === 's'){ return salary * 4 } if(performanceLevel === 'a'){ return salary * 4 } if(performanceLevel === 'b'){ return salary * 4 } } calculateBonus('s',2000) calculateBonus('a',600) ~~~ >[danger] ##### 根据策略模式的两个部分思路进行第一次重构代码 ~~~ 1.将下面的代码分成了两个部分,第一个部分就是'组合函数'就是这些条件的对应算法, 第二部分也就是执行部分'calculateBonus ' 2.但是这代码也有个问题就是会导致'calculateBonus ' 里面的条件语句越来越多 ~~~ ~~~ 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 ~~~ >[danger] ##### es5 -- 尝试用类的思想去实现一个符合后台的策略模式 ~~~ 1.下面的代码就将需要计算的部分封装成了类,Bonus 作为了Context 拥有了执行 策略的能力也就是执行这些算法类 2.定义一系列的算法,把它们各自封装成策略类,算法被封装在策略类内部的方法里。 在客户对 Context发起请求的时候,Context总是把请求委托给这些策略对象中间的某一个进行计算。 ~~~ ~~~ // 算法 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 ~~~ >[danger] ##### js 天然特性的策略模式 ~~~ 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 ~~~ >[success] # js 的策略模式 总结 ~~~ 1.引用书中引用的话'Peter Norvig在他的演讲中曾说过:“在函数作为一等对 象的语言中,策略模式是隐形的。' 2.相比java的策略模式需要建立接口建立类来维护,js天然优势就是函数是 一等公民,我们可以不用像java那么复杂来实现策略 3.书中对js的策略模式的优点总结: 3.1 策略模式利用组合、委托和多态等技术和思想,可以有效地避免多重 条件选择语句。 3.2策略模式提供了对开放—封闭原则的完美支持,将算法封装在独立的 strategy中,使得它们易于切换,易于理解,易于扩展。 3.3策略模式中的算法也可以复用在系统的其他地方,从而避免许多重复 的复制粘贴工作。 3.4在策略模式中利用组合和委托来让Context拥有执行算法的能力,这 也是继承的一种更轻便的替代方案。 4.书中对js策略模式的缺点总结: 4.1首先,使用策略模式会在程序中增加许多策略类或者策略对象,但实 际上这比把它们负责的逻辑堆砌在Context中要好(js相比java来说这个缺点就没有那么明显,java需要大量的类来维持策略) 4.2其次,要使用策略模式,必须了解所有的strategy,必须了解各个 strategy之间的不同点,这样才能选择一个合适的strategy。比如,我们要选 择一种合适的旅游出行路线,必须先了解选择飞机、火车、自行车等方案的 细节。此时strategy要向客户暴露它的所有实现,这是违反最少知识原则的 ~~~ * 代码中我们其实经常会用到策略模式,我们把代码在简化一下来看熟知的策略模式 ~~~ 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, 10000 ); // 输出:40000 ~~~