This is the second day of my participation in the August More text Challenge. For details, see: August More Text Challenge
Definition: Define a set of algorithms, encapsulate them one by one, and make them interchangeable.
Calculate bonuses using the strategy model
Take the calculation of year-end bonus as an example, for example: the performance of S year-end bonus 4 times the salary, the performance of A year-end bonus 3 times the salary, the performance of B year-end bonus 2 times, write A piece of code to realize the calculation of employee year-end bonus.
1 Initial code implementation
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) / / output: 40000
calculateBonus( 'S'.6000 ); / / output: 24000
Copy the code
As you can see, this code is very simple, but it has a number of obvious drawbacks.
calculateBonus
Contains a lot ofif-else
Statement, need to override all logical branches.calculateBonus
Inflexible, if you increase the performance C, or adjust the bonus factor, you have to go back in depthcalculateBonus
Function to modify, this is a violation of the open – close principle.- Algorithm reusability check, if needed elsewhere, only copy and paste.
Refactor the code using composite functions
All kinds of algorithms are encapsulated into a small function, these small functions have a good name, you can know which algorithm at a glance, they can also be reused.
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) / / output: 30000
Copy the code
Refactor the code using policy mode
The strategy pattern refers to defining a set of algorithms and encapsulating them one by one. Separating the unchanging from the changing is the theme of every design pattern, and the purpose of the policy pattern is to separate the use of an algorithm from its implementation.
A program based on the policy pattern consists of at least two parts. The first is a set of policy classes that encapsulate specific algorithms and are responsible for specific computing processes. The second part is the environment class Context, which accepts requests from customers and then delegates them to one of the policy classes.
The first version mimics the implementation in traditional object-oriented languages by encapsulating each performance calculation rule in a corresponding policy class:
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
}
Copy the code
Next define Bonus:
var Bonus = function() {
this.salary = null // The original salary
this.strategy = null // The policy object corresponding to the performance level
}
Bonus.prototype.setSalary = function(salary) {
this.salary = salary // Set the original salary of the employee
}
Bonus.prototype.setStrategy = function(strategy) {
this.strategy = strategy // Set performance pay for employees
}
Bonus.prototype.getBouns = function() {
return this.strategy.calculate(this.salary) // The operation of calculating bonuses is delegated to the corresponding policy object
}
Copy the code
The idea of the strategy pattern: define a set of algorithms, encapsulate them one by one, and make them interchangeable. It appears in JavaScript that they have the same goal and intent
Next, complete the rest of the code. Create a Bonus object and give it some raw data. Pass the policy object for calculating bonuses into the Bonus object internal store as well. When bonus. GetBonus () is called to calculate the bonus, the Bonus object does not have the ability to calculate by itself, instead delegating the request to a previously saved policy object.
var bonus = new Bonus()
bonus.setSalary(10000)
bonus.setStrategy(new performanceS()) // Set the policy object
console.log(bonus.getBonus()) / / output: 40000
bonus.setStrategy(new performanceA()) // Set the policy object
console.log(bonus.getBonus()) / / output: 30000
Copy the code
JavaScript version of policy mode
In JavaScript, functions are also objects, so it’s simpler and more straightforward to define strategy directly as a function:
var strategies = {
S: function(salary) {
return salary * 4
},
A: function(salary) {
return salary * 3
},
B: function(salary) {
return salary * 2}}Copy the code
Again, Context doesn’t necessarily have to be a Bonus class, so define calculateBonus.
var calculateBonus = function(level, salary) {
return strategies[level](salary)
}
console.log(calculateBonus('S'.20000)) / / output: 80000
console.log(calculateBonus('A'.10000)) / / output: 30000
Copy the code
Use the policy pattern to implement slow animation
Our goal is to get a ball moving according to a different algorithm.
The principle of achieving animation effects
The principle of using JavaScript to achieve the animation effect is the same as the production of animation, animation is some of the difference between the original painting to play a fast number of frames, to achieve visual animation effect. In JavaScript, you can animate an element by continuously adapting one of its CSS attributes, such as left, top, and background-position
Ideas and some preparation work
Before you start the exercise, you need to record some information, including at least:
- The original position of the ball when the animation begins
- The target position of the ball
- The exact point in time when the animation starts
- The duration of the ball movement
Then, use setInterval to create a timer that cycles every 19ms. In each frame of the timer, pass the elapsed time of the animation, the original position of the ball, the target position of the ball, and the total duration of the animation into the slow algorithm to calculate the current position of the ball. Then update the CSS properties corresponding to the div. Then the ball can move smoothly.
Get the ball moving
The easing algorithm accepts four parameters, meaning the elapsed time of the animation, the original position of the ball, the target position of the ball, and the total duration of the animation, and returns the value of the current position of the animation element.
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; }};Copy the code
The following code takes the idea from the jQuery library to place a div on the page:
<body>
<div style="position: absolute; background: blue" id="div">I am a div</div>
</body>
Copy the code
Next we define the Animate class. The Animate constructor takes one parameter: the DOM node to be moved.
var Animate = function (dom) {
this.dom = dom; // The DOM node that moves
this.startTime = 0; // Start time of the animation
this.startPos = 0; // The position of the DOM node when the animation starts, that is, the initial position of the DOM
this.endPos = 0; // The position of the DOM node at the end of the animation, i.e. the target position of the DOM
this.propertyName = null; // The name of the CSS property to be changed on the DOM node
this.easing = null; // Slow algorithm
this.duration = null; // Animation duration
};
Copy the code
Next, Animate. Prototype. start starts the animation, recording some information for later use when calculating the ball’s position. This method also starts the timer.
Animate.prototype.start = function (propertyName, endPos, duration, easing) {
this.startTime = +new Date(a);// Animation start time
this.startPos = this.dom.getBoundingClientRect()[propertyName]; // The initial position of the DOM node
this.propertyName = propertyName; // The DOM node is the name of the CSS property that needs to be adapted
this.endPos = endPos; // The target location of the DOM node
this.duration = duration; // Animation duration
this.easing = tween[easing]; // Slow algorithm
var self = this;
var timeId = setInterval(function () {
// Start the timer to start the animation
if (self.step() === false) {
// If the animation has finished, clear the timer
clearInterval(timeId); }},19);
};
Copy the code
The Animate. Prototype. start method takes the following four arguments:
propertyName
: To changecss
Property name, for exampleleft
,top
, indicating left and right movement and up and down movement respectively.endPos
: The target position of the ball.duration
: Duration of the animation.easing
: Easing algorithm.
Animate. Prototype. step represents what to do for each frame of the ball’s motion.
Animate.prototype.step = function () {
var t = +new Date(a);// Get the current time
if (t >= this.startTime + this.duration) {
// Fix the ball position at the end of the animation
this.update(this.endPos); // Update the CSS property values of the ball
return false;
}
var pos = this.easing(
t - this.startTime,
this.startPos,
this.endPos - this.startPos,
this.duration
);
// Pos is the current position of the ball
this.update(pos); // Update the CSS property values of the ball
};
Copy the code
Animate. Prototype. Update to Animate.
Animate.prototype.update = function (pos) {
this.dom.style[this.propertyName] = pos + "px";
};
Copy the code
Test it out:
var div = document.getElementById("div");
var animate = new Animate(div);
animate.start("left".500.1000."strongEaseOut");
Copy the code
More generalized “algorithm”
The strategy pattern refers to defining a set of algorithms and encapsulating them.
By definition, policy patterns are used to encapsulate algorithms. But using strategy patterns only to encapsulate algorithms is overkill. Practical development often spreads the meaning of algorithms so that policy patterns can also be used to encapsulate a set of “business rules.” As long as the business rules point to the same goal and can be used instead, we can use the policy pattern for encapsulation.
Advantages and disadvantages of the strategic pattern
Advantages:
- The strategy pattern can effectively avoid multiple conditional selection statements by using techniques and ideas such as composition, delegation and polymorphism.
- The strategy pattern provides perfect support for the open-close principle, encapsulating the algorithm in a separate
strategy
To make them easy to switch, easy to understand, and easy to extend. - Algorithms in the policy pattern can also be reused elsewhere in the system, avoiding a lot of duplicated copy-and-paste work.
- Use composition and delegation in the policy pattern to make
Context
The ability to execute algorithms is also a lighter alternative to inheritance.
Disadvantages:
- Using the policy pattern adds many policy classes or policy objects to your program
- All must be understood to use the policy pattern
strategy
, to understand eachstrategy
Between the differences in order to choose a suitable.
One last word
If this article is helpful to you, or inspired, please help to like and follow it, your support is the biggest motivation for me to keep writing, thank you for your support.