directory

  1. define
  2. Scenario code that can be improved
  3. Instead of modifying the original method directly, add functionality via external functions that reference the original method through the decorator pattern
  4. The actual scene
  5. Decorator mode benefits
  6. reference
  7. conclusion

A, definitions,

The decorator pattern allows you to dynamically assign responsibilities to an object while running the program without changing the object itself.

Usage scenario: Similar to interceptor, add object pre – and post-events, etc.

The decorator pattern is to dynamically add functionality to an object

Improved scenario code


const Ican =  {
    canEnglish: () = > {
        console.log('I can speak English')},canFrench: () = > {
        console.log('I can speak French')},init: function () {
        this.canEnglish()
        this.canFrench()
    }
}

Ican.init()
// I can speak English
// I can speak French now
Copy the code

Later, I learned German, and Russian? In most cases, we will choose to modify the Ican method directly, as follows:

const Ican =  {
    canEnglish: () = > {
        console.log('I can speak English')},canFrench: () = > {
        console.log('I can speak French')},canGerman: () = > { // Add new skills
        console.log('I know German')},init: function () {
        this.canEnglish()
        this.canFrench()
        this.canGerman()
    }
}

Ican.init()
// I can speak English
// I can speak French now
// I can speak German

Copy the code

Later, I learned other languages, so if I asked someone to change my code for me, he was worried about what would happen if I added methods directly to Ican.

Third, through the decorator mode, do not directly modify the original method, through external functions, reference the original method, add functionality

So he came up with a good idea. Instead of directly modifying the inside of Ican, he would use an external function, reference Ican, and add the ability to learn Russian to the external function.

const before = function (fn, beforeFn) {
    return function () {
        beforeFn.apply(this.arguments)
        return fn.apply(this.arguments)}}const after = function (fn, afterFn) {
    console.log('this1'.this); // Window
    return function () {
        console.log('this2'.this); / / Ican object
        const __ = fn.apply(this.arguments);
        afterFn.apply(this.arguments)
        return__}}const Ican =  {
    canEnglish: () = > {
        console.log('I can speak English')},canFrench: () = > {
        console.log('I can speak French')},canGerman: () = > { 
        console.log('I know German')},init: function () {
        this.canEnglish()
        this.canFrench()
        this.canGerman()
    }
}



after(Ican.init, function canRussian () {// Add new skills
    console.log('I've learned Russian again.')
}).apply(Ican);// Calling the function returned after()() changed the this of its return function

// I can speak English
// I can speak French now
// I can speak German
// I have learned Russian again

Copy the code

This is the decorator mode, which dynamically adds functionality to Ican without directly modifying Ican itself.

Four, the actual scene

1) Data reporting

The data reporting of custom events generally depends on the click event, so the click event should assume both the original function and the data reporting function.

1.1) Common practice

Code first:

Const loginBtnClick = () => {console.log(' to login ') console.log(' to report ')}Copy the code

There seems to be nothing wrong with such code, which is ubiquitous in projects, and evasion (procedural programming) is shameful but useful.

1.2) Decorator mode practice

The above code can be refactored through the decorator pattern for finer divisions of responsibility, looser coupling, and greater reusability.

const after = function (fn, afterFn) { return function () { const __ = fn.apply(this, arguments) afterFn.apply(this, Arguments) return __}} const showLogin = function () {console.log(' console.log ')} const log = function () { } const loginBtnClick = after(showLogin, log) loginBtnClick()Copy the code

2) Dynamically add parameters

A regular Ajax request parameter consists of type/URL/param, and when a special case occurs, a token parameter needs to be added to the Ajax parameter.

2.1) Common practice

Code first:

Const ajax = function (type, url, param) {// New token param.token = 'XXX' //... The ajax request... Omit}Copy the code

So, once again, you violate the open-closed principle by modifying the inside of an Ajax function directly.

2.2) Decorator practices

Add the token parameter to Ajax before the Ajax call through the decorator pattern as follows:

const before = function (fn, beforeFn) { return function () { beforeFn.apply(this, arguments) return fn.apply(this, arguments) } } let ajax = function (type, url, param) { console.log(arguments) // ... The ajax request... Omit} ajax = before(ajax, function (type, url, param) {console.log(param) param.token = 'XXX'}) ajax('type', 'url', {name: 'tj'})Copy the code

This reduces the responsibility of ajax functions and increases the reusability of Ajax functions,

Five advantages of decorator mode

Decorator pattern makes objects more stable and easy to reuse. Unstable functions can be added dynamically during personalization.

With decorator patterns, responsibility is divided more finely, code is loosely coupled and reusable.

Five decorator mode Demo2

Function.prototype.before = function(beforefn) {
    let _self = this;                          
    return function () {
        beforefn.apply(this.arguments);
        return _self.apply(this.arguments); }}Function.prototype.after = function(afterfn) {
    let _self = this;
    return function(){
        let ret = _self.apply(this.arguments);
        afterfn.apply(this.arguments);
        returnret; }}let func = function() {
    console.log('2');
}
Func1 and func3 are mount functions
let func1 = function() {
    console.log('1');
}
let func3 = function() {
    console.log('3');
}

func = func.before(func1).after(func3);
func();   / / 1 2 3

Copy the code

Six reference

  • 666- Decorator mode
  • Decorator mode

Seven summarizes

  • The decorator pattern is to dynamically add functionality to an object
  • Usage scenarios: ** is like an interceptor, adding pre – and post-events to an object
  • With decorator patterns, responsibility is divided more finely, code is loosely coupled and reusable.