This is the third day of my participation in the More text Challenge. For details, see more text Challenge

I am the title party (dog head to save life)

What is the decorator pattern

Simply put, the decorator pattern is about dynamically adding functionality to an object.

There is a duck object that makes makeVoice and sleeps, but because it is too young to walk, the code is as follows:

const duck =  {
    makeVoice: () = > {
        console.log('I can go quack quack.')},sleep: () = > {
        console.log('Who wouldn't go to sleep?')},init: function () {
        this.makeVoice()
        this.sleep()
    }
}

duck.init()
Copy the code

When he was 3 months old, he suddenly learned to walk. At this time, how to add the “walk” function to duck in the code? In most cases, we will choose to modify the duck duck method directly, as follows:

const duck =  {
    makeVoice: () = > {
        console.log('I can go quack quack.')},sleep: () = > {
        console.log('Who wouldn't go to sleep?')},walk: () = > {
        console.log('Ha ha ha, I can walk')},init: function () {
        this.makeVoice()
        this.sleep()
        this.walk()
    }
}

duck.init()
Copy the code

Happy time is always short, the bigger the duck gets, more and more functions. One day, you ask for leave to go out to play, and ask your friend to help you take care of the duck. Unfortunately, the duck is going to lay eggs, and your friend needs to help the duck to add a function of laying eggs. This is a bit of trouble because it is his first time to take care of the duck, and he worries about what will be affected if he directly adds methods to the duck.

So he came up with the idea of not modifying the inside of the duck directly, but using an external function, referring to the duck, and adding egg-laying functionality to the external function.

The code is as follows:

const before = function (fn, beforeFn) {
    return function () {
        beforeFn.apply(this.arguments)
        return fn.apply(this.arguments)}}const after = function (fn, afterFn) {
    return function () {
        const __ = fn.apply(this.arguments)
        afterFn.apply(this.arguments)
        return__}}const duck =  {
    makeVoice: function () {
        console.log('I can go quack quack.')},sleep: function () {
        console.log('Who wouldn't go to sleep?')},walk: function () {
        console.log('Ha ha ha, I can walk')},init: function () {
        this.makeVoice()
        this.sleep()
        this.walk()
    }
}

after(duck.init, function egg () {
    console.log('Happy laying eggs ~')
}).apply(duck)
Copy the code

This is the decorator pattern, which dynamically adds functionality to the duck without directly modifying the duck itself.

Ii. Actual scenario

1. Data report

The data reporting of custom events generally relies on click events, so the click events should not only assume the original function, but also assume the function of data reporting.

1.1 Common Practices

First the code:

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

That seems fine. This kind of code is ubiquitous in projects, and evasion (procedural programming) is shameful but useful.

1.2 Decorator pattern

The decorator pattern allows you to refactor the above code to divide responsibilities more closely, make the code loosely-coupled, and make it more reusable.


const after = function (fn, afterFn) {
    return function () {
        const __ = fn.apply(this.arguments)
        afterFn.apply(this.arguments)
        return__}}const showLogin = function () {
    console.log('Go log in')}const log = function () {
    console.log('To report')}const loginBtnClick = after(showLogin, log)

loginBtnClick()

Copy the code

2. Add parameters dynamically

A normal Ajax request parameter includes type/URL/param. When a special case breaks out, you need to add a token parameter to the Ajax parameter.

2.1 Common Practices

First the code:

const ajax = function (type, url, param) {
    // Add the token parameter
    param.token = 'xxx'
    / /... The ajax request... omit
}
Copy the code

There you have it, again violating the open-close principle and directly modifying the inside of an Ajax function.

2.2 Decorating practices

Add a token parameter to ajax before the ajax call, using decorator mode.

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... } ajax = before(ajax, function (type, url, param) {console.log(param) param.token = 'XXX'}) {name: 'tj'})Copy the code

This reduces the responsibility of Ajax functions and improves the reusability of Ajax functions,

Third, summary

This paper describes the application scenarios of decorator mode and the benefits it brings to us by giving three examples of dynamically adding function, data reporting and dynamically adding parameter to duck function.

The decorator pattern makes objects more stable and easier to reuse. Unstable features can be added dynamically during customization.

Github source code can be used for practice.

I hope you found this article helpful. Thanks for reading ❤️ ~


· Past wonderful ·

Design Patterns – Who hasn’t seen a few singletons (1)

Design Mode – What is happy Planet, What is Strategic Mode (part 2)

Design Mode – This is the Agent mode (3)

Design Patterns — Simple observer Patterns (part 4)

Design Mode – No, no, no, no, no, no, no, no.