發(fā)布訂閱模式、觀察者模式

觀察者模式(Observer Pattern)

觀察者模式定義了對象間的一種一對多的依賴關(guān)系,當(dāng)一個(gè)對象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對象都將得到通知,并自動(dòng)更新。觀察者模式屬于行為型模式,行為型模式關(guān)注的是對象之間的通訊,觀察者模式就是觀察者和被觀察者之間的通訊。

觀察者模式有一個(gè)別名叫“發(fā)布-訂閱模式”,或者說是“訂閱-發(fā)布模式”,訂閱者和訂閱目標(biāo)是聯(lián)系在一起的,當(dāng)訂閱目標(biāo)發(fā)生改變時(shí),逐個(gè)通知訂閱者。我們可以用報(bào)紙期刊的訂閱來形象的說明,當(dāng)你訂閱了一份報(bào)紙,每天都會(huì)有一份最新的報(bào)紙送到你手上,有多少人訂閱報(bào)紙,報(bào)社就會(huì)發(fā)多少份報(bào)紙,報(bào)社和訂報(bào)紙的客戶就是上面文章開頭所說的“一對多”的依賴關(guān)系。

發(fā)布訂閱模式(Pub-Sub Pattern)

其實(shí)24種基本的設(shè)計(jì)模式中并沒有發(fā)布訂閱模式,上面也說了,他只是觀察者模式的一個(gè)別稱。
但是經(jīng)過時(shí)間的沉淀,似乎他已經(jīng)強(qiáng)大了起來,已經(jīng)獨(dú)立于觀察者模式,成為另外一種不同的設(shè)計(jì)模式。
在現(xiàn)在的發(fā)布訂閱模式中,稱為發(fā)布者的消息發(fā)送者不會(huì)將消息直接發(fā)送給訂閱者,這意味著發(fā)布者和訂閱者不知道彼此的存在。在發(fā)布者和訂閱者之間存在第三個(gè)組件,稱為消息代理或調(diào)度中心或中間件,它維持著發(fā)布者和訂閱者之間的聯(lián)系,過濾所有發(fā)布者傳入的消息并相應(yīng)地分發(fā)它們給訂閱者。

舉一個(gè)例子,你在微博上關(guān)注了A,同時(shí)其他很多人也關(guān)注了A,那么當(dāng)A發(fā)布動(dòng)態(tài)的時(shí)候,微博就會(huì)為你們推送這條動(dòng)態(tài)。A就是發(fā)布者,你是訂閱者,微博就是調(diào)度中心,你和A是沒有直接的消息往來的,全是通過微博來協(xié)調(diào)的(你的關(guān)注,A的發(fā)布動(dòng)態(tài))。

觀察者模式和發(fā)布訂閱模式有什么區(qū)別?

我們先來看下這兩個(gè)模式的實(shí)現(xiàn)結(jié)構(gòu):


image.png

觀察者模式: 觀察者(Observer)直接訂閱(Subscribe)主題(Subject),而當(dāng)主題被激活的時(shí)候,會(huì)觸發(fā)(Fire Event)觀察者里的事件。

class Family {
    constructor(name, role) {
        this.name = name
        this.role = role
        // 存儲(chǔ)觀察者
        this.subs = []
    }

    publish(doing) {
        this.subs.forEach(sub => sub.cb(`${sub.subscribe.role}(${sub.subscribe.name}) 孩子(${this.name})在${doing}`))
    }
    
    subscribe(target, cb) {
        target.subs.push({
            subscribe: this,
            cb
        })
    }
}



const mom = new Family('雪殷', 'mon')
const father = new Family('重樓', 'father')
const child = new Family('地瓜', 'child')

mom.subscribe(child, (doing) => console.log(doing))
father.subscribe(child, (doing) => console.log(doing))

child.publish('做運(yùn)動(dòng)')
child.publish('玩王者榮耀')

發(fā)布訂閱模式: 訂閱者(Subscriber)把自己想訂閱的事件注冊(Subscribe)到調(diào)度中心(Topic),當(dāng)發(fā)布者(Publisher)發(fā)布該事件(Publish topic)到調(diào)度中心,也就是該事件觸發(fā)時(shí),由調(diào)度中心統(tǒng)一調(diào)度(Fire Event)訂閱者注冊到調(diào)度中心的處理代碼。

// 事件中心
const Event = {
    // 事件隊(duì)列
    events: Object.create(null),
    // 訂閱者
    on: (type, cb) => {
        let events = Event.events[type]

        if (events === undefined) {
            Event.events[type] = events = []
        }
        events.push(cb)
    },
    // 發(fā)布者
    emit: (type) => {
        let events = Event.events[type]

        if (events === undefined) return
        events.forEach(cb => cb())
    },
    off: (type, cb) => {
        if (type === 'all') return Event.events = Object.create(null)

        let events = Event.events[type]

        if (events === undefined) return
        for (let i = events.length - 1; i >= 0; i--) {
            if (events[i] === cb) {
                events.splice(i, 1)
            }
        }
    }
}

// on
Event.on('click', () => {
    console.log('click 1')
})

Event.on('change', () => {
    console.log('change 1')
})

const input = () => console.log('input 1')

Event.on('input', input)

// emit
Event.emit('click')

Event.emit('change')


// off
Event.off('click', () => {
    console.log('click 1')
})

Event.off('input', input)

Event.off('all')

console.log(Event)

【筆記不易,如對您有幫助,請點(diǎn)贊,謝謝】

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容