Introduction
Decorators provide a more flexible alternative to inheritance. Decorators are used to wrap objects with the same interface. They not only allow you to add behavior to methods, but also set methods to be called by the original object (such as the decorator's constructor).
Decorators are used to add new functions in the form of overloaded methods. This mode can add your own behavior before or after the decorator to achieve a specific purpose.
Text
So what are the benefits of the decorator pattern? As mentioned earlier, decorators are an alternative to inheritance. When the script is run, adding behavior to the subclass will affect all instances of the original class, but decorators will not. Instead, it can add new behaviors to different objects individually. As shown in the following code:
function Memory(macbook) {
This.cost = function () {
return macbook.cost() 75;
};
}
function BlurayDrive(macbook) {
This.cost = function () {
return macbook.cost() 300;
};
}
function Insurance(macbook) {
This.cost = function () {
return macbook.cost() 250;
};
}
// Usage
var myMacbook = new Insurance(new BlurayDrive(new Memory(new Macbook())));
console.log(myMacbook.cost());
The following is another example. When we call performTask on the decorator object, it not only has some decorator behaviors, but also calls the performTask function of the underlying object.
function AbstractDecorator(decorated) {
This.performTask = function () {
decorated.performTask();
};
}
function ConcreteDecoratorClass(decorated) {
This.base = AbstractDecorator;
This.base(decorated);
decorated.preTask = function () {
console.log('pre-calling..');
};
decorated.postTask = function () {
console.log('post-calling..');
};
}
var concrete = new ConcreteClass();
var decorator1 = new ConcreteDecoratorClass(concrete);
var decorator2 = new ConcreteDecoratorClass(decorator1);
decorator2.performTask();
Another thorough example:
tree.getDecorator = function (deco) {
Tree[deco].prototype = this;
Return new tree[deco];
};
tree.RedBalls = function () {
This.decorate = function () {
This.RedBalls.prototype.decorate(); // Step 7: First execute the decorate method of the prototype (this is Angel)
console.log('Put on some red balls'); // Step 8 Then output red
// Use these 2 steps as the decorate method of RedBalls
}
};
tree.BlueBalls = function () {
This.decorate = function () {
This.BlueBalls.prototype.decorate(); // Step 1: First execute the decorate method of the prototype, that is, tree.decorate()
console.log('Add blue balls'); // Step 2 Then output blue
// Use these 2 steps as the decorate method of BlueBalls
}
};
tree.Angel = function () {
This.decorate = function () {
This.Angel.prototype.decorate(); // Step 4: First execute the decorate method of the prototype (this is BlueBalls)
console.log('An angel on the top'); // Step 5 Then output angel
// Use these 2 steps as Angel’s decorate method
}
};
tree = tree.getDecorator('BlueBalls'); // Step 3: Assign the BlueBalls object to tree. At this time, getDecorator in the parent prototype is still available
tree = tree.getDecorator('Angel'); // Step 6: Assign the Angel object to tree. At this time, getDecorator in the parent prototype of the parent prototype is still available
tree = tree.getDecorator('RedBalls'); // Step 9: Assign the RedBalls object to tree
tree.decorate(); // Step 10: Execute the decorate method of the RedBalls object
Summary
The decorator pattern is a way to dynamically add more functions to existing functions. Put each function to be decorated in a separate function, and then use this function to wrap the existing function object to be decorated. Therefore , when special behavior needs to be performed, the calling code can selectively and sequentially use decoration functions to wrap objects as needed. The advantage is that the core responsibilities of the class (function) and the decoration function are separated.