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

前言

觀察者模式定義了一種一(被觀察者)對多(觀察者)的關系湃鹊。被觀察者發(fā)生改變就會通知所有的觀察者。它應用廣泛著拭,就像常用的addEventListener
發(fā)布訂閱模式從廣義上來說也是觀察者模式额获,就如《JS設計模式與開發(fā)實踐》所言:分辨模式的關鍵是意圖而不是結構装畅,結構雖不一樣,意圖卻是一樣

正文

實現方法嗽元,方法命名很多很多敛纲,隨意實現即可

觀察者模式
  • 結構
 ╭─────────────╮  Fire Event  ╭──────────────╮
 │             │─────────────>│              │
 │   Subject   │              │   Observer   │
 │             │<─────────────│              │
 ╰─────────────╯  Subscribe   ╰──────────────╯
  • 比喻
    你去一個數碼店買鼠標丰辣,恰好沒有你要的牧馬人傅物,你就和店主(目標)說有了的話通知你(訂閱),過了倆天貨到了迅诬,店主發(fā)短信(你預留的通知接口佩谷,就像實現里的update)你說到貨了(發(fā)布)
    很明顯旁壮,你和店主綁定,他知道你你知道他
  • 實現
// 被觀察者即目標
class Subject {
    constructor() {
        this._observes = []
    }
    // 訂閱
    add(ob) {
        const { _observes } = this
        const index = _observes.indexOf(ob)
        if(ob && !~index) {
            _observes.push(ob)
        }
    }
    remove(ob) {
        const { _observes } = this
        if(ob) {
            const index = _observes.indexOf(ob)
            ~index && _observes.splice(index, 1)
        }
    }
    // 發(fā)布
    notify(args) {
        this._observes.forEach(ob => {
            ob.update(args)
        })
    }
}
// 觀察者谐檀,需要提供一個接口(update)給目標抡谐,讓它可以通過這個接口傳遞更新的消息
class Observer {
    constructor(name) {
        this.name = name
    }
    update(...args) {
        console.log(`${this.name}收到了:`, args)
    }
}

// 目標告訴觀察者自己更新了,所以得建個目標對象
const subject = new Subject()
// 創(chuàng)建觀察者
const ob1 = new Observer('ob1')
const ob2 = new Observer('ob2')

subject.add(ob1)
subject.add(ob2)
subject.notify('海賊王更新到800集了')

console.error('退訂了桐猬,推送新消息')
subject.remove(ob2)
subject.notify('海賊王更新到801集了')

這種實現發(fā)布者和訂閱者綁定在一塊了麦撵,松耦合(面向接口),如此例這些Observer實現了相同的接口update,這樣子Subject就可以知道自己更新了通過什么接口通知Observer

發(fā)布訂閱模式
  • 結構
 ╭─────────────╮                 ╭───────────────╮   Fire Event   ╭──────────────╮
 │             │  Publish Event  │               │───────────────>│              │
 │  Publisher  │────────────────>│ Event Channel │                │  Subscriber  │
 │             │                 │               │<───────────────│              │
 ╰─────────────╯                 ╰───────────────╯    Subscribe   ╰──────────────╯
  • 比喻
    你在看起點(Broker)上看圣墟(topic)免胃,因為辰東(發(fā)布者)更新不規(guī)律所以你訂閱了圣墟(訂閱了圣墟事件)音五,一旦辰東更新了發(fā)到起點上,起點發(fā)現辰東更新了就會通知(發(fā)布)你小說更新了
    很明顯羔沙,辰東不知道你是誰他只管傳他的小說就是了躺涝,你也不需要知道小說是誰寫的,只需要知道你看的小說叫什么撬碟,照樣可以看的很開心
  • 實現
// 經紀人诞挨,中間站,消息中心etc
class Broker {
    constructor() {
        this.subs = {}
    }
    // 訂閱
    subscribe(topic, cb) {
        const { subs } = this
        // 需要訂閱的主題是否有人訂閱過
        const cbs = subs[topic]
        if(cbs) {
            cbs.publish(cb)
        } else {
            this.subs[topic] = [cb]
        }
    }
    unsubscribe(topic, cb) {
        const { subs } = this
        const cbs = subs[topic]
        if(cbs) {
            const index = cbs.indexOf(cb)
            if(~index) {
                cbs.splice(index, 1)
            }
        }
    }
    // 發(fā)布
    publish(topic, args) {
        (this.subs[topic] || []).forEach(cb => {
            cb(args)
        })
    }
}

const broker = new Broker()

// A訂閱了A事件呢蛤,他只關心A事件本身惶傻,至于誰發(fā)布的無所謂
broker.subscribe('A', function A(...args) {
    console.log(`A接收到了:`, args)
})

function B(...args) {
    console.log(`B接收到了:`, args)
}
// B訂閱了B事件,他只關心A事件本身其障,至于誰發(fā)布的無所謂
broker.subscribe('B', B)

// XX發(fā)布了A事件银室,他只關心他發(fā)了什么,誰接收的無所謂
broker.publish('A', '海賊王更新到800集了')
// XX發(fā)布了B事件
broker.publish('B', '海賊王更新到800集了')

// B退訂了B事件
broker.unsubscribe('B', B)

// XX發(fā)布了A事件
broker.publish('A', '海賊王更新到801集了')
// XX發(fā)布了B事件
broker.publish('B', '海賊王更新到801集了')

發(fā)布訂閱模式里励翼,發(fā)布者和訂閱者完全解耦蜈敢,互不關心,只關心消息本身即可

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
  • 序言:七十年代末汽抚,一起剝皮案震驚了整個濱河市抓狭,隨后出現的幾起案子,更是在濱河造成了極大的恐慌造烁,老刑警劉巖否过,帶你破解...
    沈念sama閱讀 218,607評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現場離奇詭異惭蟋,居然都是意外死亡苗桂,警方通過查閱死者的電腦和手機,發(fā)現死者居然都...
    沈念sama閱讀 93,239評論 3 395
  • 文/潘曉璐 我一進店門告组,熙熙樓的掌柜王于貴愁眉苦臉地迎上來煤伟,“玉大人,你說我怎么就攤上這事木缝”阆牵” “怎么了?”我有些...
    開封第一講書人閱讀 164,960評論 0 355
  • 文/不壞的土叔 我叫張陵我碟,是天一觀的道長鸿秆。 經常有香客問我,道長怎囚,這世上最難降的妖魔是什么卿叽? 我笑而不...
    開封第一講書人閱讀 58,750評論 1 294
  • 正文 為了忘掉前任桥胞,我火速辦了婚禮,結果婚禮上考婴,老公的妹妹穿的比我還像新娘贩虾。我一直安慰自己,他們只是感情好沥阱,可當我...
    茶點故事閱讀 67,764評論 6 392
  • 文/花漫 我一把揭開白布缎罢。 她就那樣靜靜地躺著,像睡著了一般考杉。 火紅的嫁衣襯著肌膚如雪策精。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,604評論 1 305
  • 那天崇棠,我揣著相機與錄音咽袜,去河邊找鬼。 笑死枕稀,一個胖子當著我的面吹牛询刹,可吹牛的內容都是我干的。 我是一名探鬼主播萎坷,決...
    沈念sama閱讀 40,347評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼凹联,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了哆档?” 一聲冷哼從身側響起蔽挠,我...
    開封第一講書人閱讀 39,253評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎瓜浸,沒想到半個月后澳淑,有當地人在樹林里發(fā)現了一具尸體,經...
    沈念sama閱讀 45,702評論 1 315
  • 正文 獨居荒郊野嶺守林人離奇死亡斟叼,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,893評論 3 336
  • 正文 我和宋清朗相戀三年偶惠,在試婚紗的時候發(fā)現自己被綠了春寿。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片朗涩。...
    茶點故事閱讀 40,015評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖绑改,靈堂內的尸體忽然破棺而出谢床,到底是詐尸還是另有隱情,我是刑警寧澤厘线,帶...
    沈念sama閱讀 35,734評論 5 346
  • 正文 年R本政府宣布识腿,位于F島的核電站,受9級特大地震影響造壮,放射性物質發(fā)生泄漏渡讼。R本人自食惡果不足惜骂束,卻給世界環(huán)境...
    茶點故事閱讀 41,352評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望成箫。 院中可真熱鬧展箱,春花似錦、人聲如沸蹬昌。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,934評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽皂贩。三九已至栖榨,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間明刷,已是汗流浹背婴栽。 一陣腳步聲響...
    開封第一講書人閱讀 33,052評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留遮精,地道東北人居夹。 一個月前我還...
    沈念sama閱讀 48,216評論 3 371
  • 正文 我出身青樓,卻偏偏與公主長得像本冲,于是被迫代替她去往敵國和親准脂。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,969評論 2 355