第5章 策略模式

第二部分 设计模式

第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')
	

  

posted on 2018-11-19 18:33  huyanluanyu1989  阅读(112)  评论(0编辑  收藏  举报