JavaScript strategy pattern application

Recently, I have been reading the book "JavaScript Design Patterns and Development Practices", and I have benefited a lot. Record the demos in the book to deepen your understanding.

Separating the unchanged part from the changed part is the theme of each design pattern, and the strategy pattern is no exception. The purpose of the strategy pattern is to separate the use of the algorithm from the implementation of the algorithm.

The definition of the strategy pattern is: define a series of algorithms, encapsulate them one by one, and make them replace each other.

A program based on a strategy pattern consists of at least two parts. The first part is a set of strategy classes, which encapsulate specific algorithms and are responsible for the specific calculation process. The second part is the environment class Context, which accepts client requests and then delegates the request to a strategy class. To do this, it means that a reference to a strategy object should be maintained in the Context.

demo1:

Many companies ’year-end awards are based on employee salary bases and year-end performance. For example, a person with performance S has a year-end reward of 4 times the salary, a person with performance A has a year-end salary of 3 times, and a person with performance B has a year-end reward of 2 times the salary. Suppose the finance department asks us to provide a code to facilitate them to calculate the year-end bonus of employees. Implementing this with JS is simple:

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); // 输出:40000
calculateBonus('S', 6000); // 输出:24000

This code is very simple, but the disadvantages are obvious:

  1. The calculateBonus function is relatively large and contains many if-else statements, which need to cover all logical branches.
  2. The calculateBonus function lacks flexibility. If a new performance level C is added, or if the bonus coefficient of performance S is changed to 5, then we must go deep into the internal implementation of the calculateBonus function, which violates the open and closed principle.
  3. The reusability of the algorithm is poor. What if we need to reuse these algorithms for calculating bonuses elsewhere in the program? Our choice is only copy and paste.

At this time, the strategy mode is used; see the code:

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

By refactoring the code using the above strategy pattern, we 消除了原程序中大片的条件分支语句. All the logic related to calculating the bonus is no longer placed in the Context, but instead 分布在各个策略对象中. Context does not have the ability to calculate bonuses, but rather this responsibility 委托给了某个策略对象, the algorithm responsible for each strategy object has been encapsulated within the object.

demo2 implements a DIV of movement in js:

Use the strategy mode to achieve the following:

<!DOCTYPE html>
<html>
<head>
	<meta charset="utf-8">
	<meta http-equiv="X-UA-Compatible" content="IE=edge">
	<title>javascript策略模式的应用!</title>
</head>
<body>
<div style="position:absolute;background:blue; width: 100px;height: 100px;color: #fff;" id="div">我是div</div>
	<script>
 
		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;
			}
		};
		var Animate = function(dom) {
			this.dom = dom; // 进行运动的dom 节点
			this.startTime = 0; // 动画开始时间
			this.startPos = 0; // 动画开始时,dom 节点的位置,即dom 的初始位置
			this.endPos = 0; // 动画结束时,dom 节点的位置,即dom 的目标位置
			this.propertyName = null; // dom 节点需要被改变的css 属性名
			this.easing = null; // 缓动算法
			this.duration = null; // 动画持续时间
		};
		Animate.prototype.start = function(propertyName, endPos, duration, easing) {
			this.startTime = +new Date; // 动画启动时间
			this.startPos = this.dom.getBoundingClientRect()[propertyName]; // dom 节点初始位置
			this.propertyName = propertyName; // dom 节点需要被改变的CSS 属性名
			this.endPos = endPos; // dom 节点目标位置
			this.duration = duration; // 动画持续事件
			this.easing = tween[easing]; // 缓动算法
			var self = this;
			var timeId = setInterval(function() { // 启动定时器,开始执行动画
				if (self.stop() === false) { // 如果动画已结束,则清除定时器
					clearInterval(timeId);
				}
			}, 19);
		};
		Animate.prototype.stop = function() {
			var t = +new Date; // 取得当前时间
			if (t >= this.startTime + this.duration) { // (1)
				this.update(this.endPos); // 更新小球的CSS 属性值
				return false;
			}
			var pos = this.easing(t - this.startTime, this.startPos,
				this.endPos - this.startPos, this.duration);
			// pos 为小球当前位置
			this.update(pos); // 更新小球的CSS 属性值
		};
		Animate.prototype.update = function(pos) {
			this.dom.style[this.propertyName] = pos + 'px';
		};

		var div = document.getElementById('div');
		var animate = new Animate(div);
		animate.start('left', 500, 1000, 'strongEaseOut');

	</script>
</body>
</html>

We use the strategy mode to pass the algorithm into the animation class to achieve a variety of slow motion effects. These algorithms can be easily replaced with another algorithm. This is one of the classic applications of the strategy mode. Implement the strategy pattern is not complicated, the key is how to implement the strategy pattern from behind, find 封装变化, 委托and 多态性these 思想的价值.

Published 398 original articles · Liked 182 · Visits 370,000+

Guess you like

Origin blog.csdn.net/yexudengzhidao/article/details/105505344
Recommended