Decorator mode

The decorator pattern can dynamically add additional responsibilities to an object without affecting other objects derived from that class.

Two features:

1. Add new functions to the object

2. Do not change its original structure and function

What decorators do:

1. Add functionality to a class without modifying the source code

2. Add functionality to a class

3. Dynamically add or remove features

Several ways to implement the decorator pattern

Use “class” to implement

For example, when sun Wukong first jumps out of the stone, he has only sayName and Attack. Only after he goes to the East China Sea and gets the Staff will he be able to add a new skill, GoldGun. If you want to add this skill to him without modifying the source code, you can use decorator mode.

// a Monkey class. The purpose is to add new functionality to the Monkey class
    function Monkey(){
        console.log("On a dark and windy night, a monkey jumped out of a stone. It was Sun Wukong.")
    }
    Monkey.prototype = {
        sayName:function (){
            console.log("I am Monkey King.")},attack:function (){
            console.log("Monkey Punch.")}}// Create a decorator and receive a decorator object
    var Decorator = function (monkey){
        this.monkey = monkey
    }
    Decorator.prototype = {
        sayName:function (){
            this.monkey.sayName()
        },
        attack:function (){
            this.monkey.attack()
        }
    }

    // Create a concrete decorator object
    var GoToDongHai = function (name){ // Receive an instance object
        Decorator.call(this,name) // call executes, pointing this to the instance object changed to GoToDongHai
    }

    var monkey = new Monkey() // Generate an instance object called monkey

    GoToDongHai.prototype = new Decorator(monkey) // Pass the instance object monkey to the decorator, and the new decorator generates the prototype of the instance object assigned to the decorator object

    GoToDongHai.prototype.GoldGun = function (){ // And add new attributes to its prototype
        console.log("Get the staff and eat me.")}var dongHai = new GoToDongHai(monkey) // Generate instance object dongHai

    dongHai.sayName()
    dongHai.attack()
    dongHai.GoldGun() // Now you can acquire new skills without modifying the original code
Copy the code

By nesting recursively

For example, at first the fighter jet could only fire ordinary bullets, but it needed to be added to fire missiles and even atomic bombs.

var Plane = function(){}

Plane.prototype.fire = function(){
    console.log( 'Fire ordinary bullets' );
};

var MissileDecorator = function(plane){
    this.plane = plane;
};

MissileDecorator.prototype.fire = function(){
    this.plane.fire(); 
    console.log( 'Launch a missile' );
};

var AtomDecorator = function(plane){
    this.plane = plane;
};

AtomDecorator.prototype.fire = function(){
    this.plane.fire();
    console.log( 'Launch an atomic bomb' );
};

var plane = new Plane();

plane = new MissileDecorator(plane);
plane = new AtomDecorator(plane); // Equivalent to Plane = new AtomDecorator(New MissileDecorator(plane))
plane.fire(); // Fire ordinary bullets fire missiles fire atomic bombs
Copy the code

This way of dynamically adding responsibility to an object does not really change the object itself, but puts the object into another object, which is referred to in a chain, forming an aggregate object. These objects all have the same interface (fire method), and when a request reaches an object in the chain, that object performs its own operation and then forwards the request to the next object in the chain.

Because the decorator object and the object it decorates have a consistent interface, they are transparent to the client using the object, and the decorator object does not need to know that it has been decorated. this transparency allows us to recursively nest any number of decorator objects.

Modifying object methods

The JavaScript language makes it fairly easy to change objects on the fly. You can rewrite an object or a method of an object directly without using a “class” to implement the decorator pattern

var plane = {
    fire: function(){
        console.log( 'Fire ordinary bullets'); }}var missileDecorator = function(){
    console.log( 'Launch a missile' );
}

var atomDecorator = function(){
    console.log( 'Launch an atomic bomb' );
}

var fire1 = plane.fire;

plane.fire = function(){
    fire1();
    missileDecorator();
}

var fire2 = plane.fire;

plane.fire = function(){
    fire2();
    atomDecorator();
}

plane.fire();// Separate output: firing ordinary bullets, firing missiles, firing atomic bombs
Copy the code

Decorative function

It’s easy to extend properties and methods on an object in JavaScript, but it’s hard to add extra functionality to a function without changing its source code. It’s hard to get into a function’s execution environment while the code is running.

Function.prototype.before = function( beforefn ){
    var __self = this; // Save a reference to the original function

    return function(){ // Returns a "proxy" function that contains both the original function and the new function

        beforefn.apply( this.arguments ); 
 	    // Execute the new function and ensure that this is not hijacked
        // The new function is executed before the original function

        return __self.apply( this.arguments ); 
	    // Execute the original function and return the result of the original function.
        // And make sure this is not hijacked}}Function.prototype.after = function( afterfn ){
    var __self = this;

    return function(){
        var ret = __self.apply( this.arguments );
        afterfn.apply( this.arguments );
        return ret
    }
};

function f1() {
    console.log(1)}let f2 = f1.before(function () {
    console.log(0)});let f3 = f2.after(function () {
    console.log(2)
})

f3() // Print 0, 1, 2

Copy the code

The difference between decorator mode and proxy mode

The structure of the decorator pattern and the proxy pattern look very similar. Both patterns describe how to provide some degree of indirect reference to an object, and their implementation parts retain a reference to another object and send requests to that object.

The Proxy pattern emphasizes a relationship (between a Proxy and its entities) that can be expressed statically, that is, it can be determined at the outset.

The decorator pattern is used when the full functionality of an object is initially uncertain.

The proxy pattern typically has only one layer of proxy: a reference to the ontology;

Decorator patterns often form a long chain of decorators.