設計模式-不會吧,不會還有人不知道裝飾器模式吧(五)

這是我參與更文挑戰的第3天,活動詳情查看: 更文挑戰javascript

大佬們輕噴~我是標題黨(狗頭保命)java

1、什麼是裝飾器模式

簡單來講,裝飾器模式就是給對象動態增長功能。git

有一個鴨子對象,它會發聲 makeVoice, 會睡覺 sleep,可是由於它還過小,不會走路,代碼以下:github

const duck =  {
    makeVoice: () => {
        console.log('我會嘎嘎嘎啦')
    },
    sleep: () => {
        console.log('誰又不會睡覺呢')
    },
    init: function () {
        this.makeVoice()
        this.sleep()
    }
}

duck.init()
複製代碼

當它 3 個月大的時候,忽然學會走路 walk 了,這個時候,怎麼在代碼中,爲鴨子 duck 添加走路 walk 功能呢?大多數狀況下,咱們會選擇直接修改鴨子 duck 方法,代碼以下:web

const duck =  {
    makeVoice: () => {
        console.log('我會嘎嘎嘎啦')
    },
    sleep: () => {
        console.log('誰又不會睡覺呢')
    },
    walk: () => {
        console.log('哈哈哈,我會走路啦')
    },
    init: function () {
        this.makeVoice()
        this.sleep()
        this.walk()
    }
}

duck.init()
複製代碼

快樂的時光老是短暫的,鴨子越長越大,功能也愈來愈多。有一天,你請假出去玩,拜託朋友幫你照顧這隻鴨子,不巧,鴨子要下蛋了,朋友須要幫鴨子添加一個下蛋的功能,這就有點麻煩了由於這是他第一次照顧這隻鴨子,他擔憂若是直接在鴨子內部添加方法會影響到什麼。ajax

因而他想到了一個好方法,不直接修改鴨子內部,而是經過一個外部函數,引用這個鴨子,併爲外部函數添加下蛋的功能。編程

代碼以下:設計模式

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('我會嘎嘎嘎啦')
    },
    sleep: function () {
        console.log('誰又不會睡覺呢')
    },
    walk: function () {
        console.log('哈哈哈,我會走路啦')
    },
    init: function () {
        this.makeVoice()
        this.sleep()
        this.walk()
    }
}

after(duck.init, function egg () {
    console.log('生蛋快樂~')
}).apply(duck)
複製代碼

這就是裝飾器模式,動態的爲鴨子添加功能,而不直接修改鴨子自己。markdown

2、實際場景

1. 數據上報

自定義事件的數據上報通常都依賴於點擊事件,那麼這個點擊事件既要承擔本來的功能,又要承擔數據上報的功能。app

1.1 普通作法

先上代碼:

const loginBtnClick = () => {
    console.log('去登陸')
    console.log('去上報')
} 
複製代碼

好像沒毛病,這樣的代碼中項目中隨處可見,逃避(面向過程編程)雖可恥但有用。

1.2 裝飾器模式作法

能夠經過裝飾器模式來重構上述代碼,將職責劃分更細,代碼鬆耦合,可複用性更高。

const after = function (fn, afterFn) {
    return function () {
        const __ = fn.apply(this, arguments)
        afterFn.apply(this, arguments)
        return __
    }
}

const showLogin = function () {
    console.log('去登陸')
}

const log = function () {
    console.log('去上報')
}

const loginBtnClick = after(showLogin, log)

loginBtnClick()

複製代碼

2. 動態增長參數

一個常規的 ajax 請求參數包括 type / url / param,當突發一個特殊狀況,須要在 ajax 的參數中,新增一個 token 參數。

2.1 普通作法

先上代碼:

const ajax = function (type, url, param) {
    // 新增token參數
    param.token = 'xxx'
    // ...ajax請求...省略
}
複製代碼

好了,又一次違反開放-封閉原則,直接修改了 ajax 函數內部.

2.2 裝飾器作法

經過裝飾器模式,在 ajax 調用以前,爲 ajax 增長 token 參數,代碼以下:

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)
    // ...ajax請求...省略
}

ajax = before(ajax, function (type, url, param) {
    console.log(param)
    param.token = 'xxx'
})

ajax('type', 'url', {name: 'tj'})
複製代碼

這樣作能夠減小 ajax 函數的職責,提升了 ajax 函數的可複用性,

3、總結

本文經過給鴨子函數動態增長功能、數據上報、動態增長參數 3 個例子,講述了裝飾器模式的應用場景及帶給咱們的好處。

裝飾器模式,讓對象更加穩定,且易於複用。而不穩定的功能,則能夠在個性化定製時進行動態添加。

可經過 github源碼 進行實操練習。

但願本文能對你有所幫助,感謝閱讀❤️~


· 往期精彩 ·

【設計模式-誰沒碰見過幾個單例模式(一)】

【設計模式-什麼是快樂星球,什麼是策略模式(二)】

【設計模式-原來這就是代理模式(三)】

【設計模式-簡單易懂的觀察者模式(四)】

【設計模式-不會吧,不會還有人不知道裝飾器模式吧(五)】

相關文章
相關標籤/搜索