第二部分 设计模式
第5章 策略模式
定义:定义一系列算法,把它们一个个封装起来,并且使它们可以相互替换。
其实就是定义一系列的算法,把他们各自封装成策略类,算法被封装在策略类内部的方法里。在对Context发起请求的时候,Context总是把请求委托给这些策略对象中间的某一个进行计算。
5.1 使用策略模式计算奖金
/** * 使用策略模式计算奖金 * S 4个月奖金 * A 3个月奖金 * B 2个月奖金 */ //1、最原始实现方式 //缺点: //(1)calculate函数比较庞大,包含了很多判断语句,这些语句必须包含所有的逻辑分支 //(2)函数缺乏弹性,如果增加了新的绩效等级,或者想把绩效等级的奖金系数修改一下,我们必须深入calculate函数内部实 //现违反了开放-封闭原则 //算法的复用性差,如果在程序的其它地方用到这些算法,我们只能复制粘帖 var calculateBonus = function(performanceLevel, salary){ switch(performanceLevel){ case 'S': return salary*4 break case 'A': return salary*3 break case 'B': return salary*2 break default: return salary break } } console.log(calculateBonus('A',10000))
//2、使用组合函数重构代码 //优点:(1)把各种算法封装到一个个的小函数里,可以一目了然的知道对应的哪种算法 //(2)复用性强 //缺点:calculateBouns函数会越来越庞大,在系统变化的时候缺乏弹性 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){ switch(performanceLevel){ case 'S': return performanceS(salary) break case 'A': return performanceA(salary) break case 'B': return performanceB(salary) break } } console.log(calculateBonus('B',10000))
//3、使用策略模式重构代码,将不变的部分和变化的部分隔离开来,策略模式的目的就是将算法的使用和 //算法的实现分离开来。 //一个基于策略模式的程序至少由两部分组成。 //第一部分是策略类,策略类封装了具体的算法,并负责具体的计算过程。 //第二部分是环境类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())
5.2 JavaScript中函数形式的策略模式
//javaScript中函数形式的策略模式 var strategy = { 'S': function(salary){ return salary*4 }, 'A': function(salary){ return salary*3 }, 'B': function(salary){ return salary*2 } } var calculateBonus = function(level,salary){ return strategy[level](salary) } console.log(calculateBonus('A',10000))
5.3 使用策略模式实现缓动动画
<div id="div" style="position: absolute;background: blue">我是DIV</div>
/** * [tween 动画缓动的算法] * @type {Object} * t 动画已消耗时间 * b 原始位置 * c 目标位置 * d 动画持续时间 */ var tween = { linear: function(t, b, c, d){ return c*t/d + b }, easeIn: function(t, b, c, d){ return c * (t /= d) * t + b }, strongEaseIn: function(t, b, c, d){ return c * ( t /= d ) * t * t * t * t + b; }, strongEaseOut: function(t, b, c, d){ return c * ( ( t = t / d - 1) * t * t * t * t + 1 ) + b; }, sineaseIn: function( t, b, c, d ){ return c * ( t /= d) * t * t + b; }, sineaseOut: function(t,b,c,d){ return c * ( ( t = t / d - 1) * t * t + 1 ) + b; } } /** * [Animate description] * @param {[type]} dom [description] */ var Animate = function(dom){ this.dom = dom //进行运动的dom节点 this.startTime = 0 //动画开始时间 this.startPos = 0 //动画开始时dom节点的初始位置 this.endPos = 0 //动画结束时dom节点的目标位置 this.propertyName = null //dom节点需要改变的css属性 this.easing = null //缓动算法 this.duration = null //动画持续时间 } /** * [start 动画启动] * @param {[type]} propertyName [dom节点需要改变的css属性,如left、right、top] * @param {[type]} endPos [动画结束时dom节点的目标位置] * @param {[type]} duration [动画持续时间] * @param {[type]} easing [缓动算法] * @return {[type]} [description] */ Animate.prototype.start = function(propertyName, endPos, duration, easing){ this.startTime = +new Date() //获取当间时间 //getBoundingClientRect获取元素位置 this.startPos = this.dom.getBoundingClientRect()[propertyName] //dom节点初始位置 this.propertyName = propertyName this.endPos = endPos this.duration = duration this.easing = tween[easing] var self = this //启动定时器,开始执行动画 var timeId = setInterval(function(){ //如果动画结束清除定时器 if(self.step() === false){ clearInterval(timeId) } },19) } /** * [step 动画运动的每一帧要做的事] * @return {[type]} [description] */ Animate.prototype.step = function(){ var t = +new Date() //取得当前时间 if(t >= this.startTime + this.duration){ this.update(this.endPos) return false } //dom当前位置 var pos = this.easing(t - this.startTime, this.startPos, this.endPos, this.duration) //更新dom当前位置信息 this.update(pos) } /** * [update 更新动画运动的位置] * @param {[type]} pos [当前动画的位置] * @return {[type]} [description] */ Animate.prototype.update = function(pos){ this.dom.style[this.propertyName] = pos + 'px' } var div = document.getElementById('div') var animate = new Animate(div) animate.start('right',500, 1000, 'easeIn')