發布-訂閱模式,簡單了解。
- 觀察者模式(Observer)
- 發布訂閱模式(Pubilsh/Subscribe)
- 總結
1.觀察者模式(Observer)
觀察者模式,從字面理解至少需要一個觀察者,如果有觀察者,猜想也還需要被觀察的主題?
文字描述如下:
觀察者模式是一種設計模式:其中一個對象(稱為Subject),維持一系列依賴於它的(觀察者)對象,將有關狀態的任何變更自動通知給它們(觀察者)
畫圖描述如下:
Subject(目標):維護一系列的(對這個主題感興趣)觀察者,方便 添加,刪除,通知觀察者
Observer(觀察者):在(感興趣的)主題通知觀察者自己狀態變化時,做改變。觀察者提供一個更新接口(更新自己)
有了以上的概念,代碼簡單實現如下:
// 主題,接收對自己感興趣的觀察者,觸發每個觀察者 class Subject { constructor(name) { this.state = 0 this.name = name // 存儲一系列的(對這個主題感興趣)觀察者 this.observers = [] } addObservers(observer) { // 添加 this.observers.push(observer) } removeObservers(observer) { // 刪除 this.observers = tthis.observers.filter(item => item != observer) } notifyObservers() { // 通知 var observers = this.observers for (var i = 0, j = observers.length; i < j; i++) { observers[i].update(this.name) } } changeState(state) { this.state = state } } // 觀察者,等待被觸發 class Observer { constructor(name) { this.name = name } update(topic) { // 更新自己,對主題變化做響應 console.log(`${this.name}訂閱的${topic}更新了, ${this.name}: 做了更新操作`) } subscribe(subject) { subject && subject.addObservers(this) } } let book = new Subject('book') let coffee = new Subject('coffee') let xiaobu = new Observer('小布') // xiaobu 對book這個主題感興趣,訂閱了book xiaobu.subscribe(book) // xiaobu 對coffee感興趣,訂閱了coffee xiaobu.subscribe(coffee) book.changeState(2) book.notifyObservers()
在實際項目框架中的應用,舉個例子(不了解vue的,可以暫時跳過,不影響理解):
Vue的數據雙向綁定實現就采用了觀察者模式。
主題 Dep ,觀察者Watcher 。
數據在get部分:收集依賴
數據在set部分:派發通知
代碼部分截取:
export default class Dep { constructor () { this.id = uid++ this.subs = [] } addSub (sub: Watcher) { // 添加 this.subs.push(sub) } removeSub (sub: Watcher) { // 刪除 remove(this.subs, sub) } depend () { // 調用觀察者的 添加感興趣的主題 if (Dep.target) {// (Dep.target 記錄了當前的觀察者 Dep.target.addDep(this) // 觀察者 對這個 主題感興趣 } } notify () { // 通知 for (let i = 0, l = subs.length; i < l; i++) { subs[i].update() } } } class Watcher { constructor ( vm: Component, cb: Function ) { this.vm = vm this.cb = cb } addDep (Dep) { // 添加感興趣的主題 dep.addSub(this) } update () { // 觸發更新 /* istanbul ignore else */ if (this.lazy) { this.dirty = true } else if (this.sync) { this.run() } else { queueWatcher(this) } } } // 數據響應式 function defineReactive (object, key, value) { // dep 存儲一系列的(對這個數據感興趣)觀察者 const dep = new Dep() Object.defineProperty(obj, key, { get() { if (Dep.target) { // 觀察者添加主題 dep.depend() // dep.depend() = Dep.target.addDep(this) } }, set(newVal) { dep.notify() // 通知所有人數據更新了 } }) }
2.發布/訂閱模式(Pubilsh/Subscribe)
在JavaScript 講設計模式的書里面 通常會看見一句話, 發布訂閱模式 又叫做 觀察者模式
發布訂閱模式 是 觀察者模式 的一種實現(有所變化)
文字描述如下:
發布訂閱(Publish/Subscriber)模式使用了一個 主題/事件通道對象,管理 主題和事件
Publish:發布者,發布通知 (通知 主題/事件通道對象 這個主題變化了,執行對應的事件)
Subscriber:訂閱者,注冊主題,和事件( 告訴 主題/事件通道對象,這個主題變換,對應執行事件)
畫圖描述如下:
有了以上的概念,代碼簡單實現如下:
let eventTopic = {} class Pushlish { // 發布者,發布通知 (通知 主題/事件通道對象 這個主題變化了,執行對應的事件) update (topic, ...rest) { eventTopic[topic]&&eventTopic[topic].forEach(listener => listener.apply(null,rest)) } } class Subscriber { // 訂閱者,注冊主題,和事件( 告訴 主題/事件通道對象,這個主題變換,對應執行事件) subscribe (topic,event) { if(eventTopic[topic]) { eventTopic[topic].push(event) } else { eventTopic[topic] = [event] } } } let publish = new Pushlish() let subscribe = new Subscriber() subscribe.subscribe('book',(name)=>{ console.log(`${name}訂閱的book更新了, ${name}: 做了更新操作`) }) publish.update('book','小布')
然后代碼分裝整合如下:
class EventTopic { constructor() { this._eventTopic = {} } subscribe (topic,event) { if(this._eventTopic[topic]) { this._eventTopic[topic].push(event) } else { this._eventTopic[topic] = [event] } } update (topic, ...rest) { this.events[type]&&this.events[type].forEach(listener => listener.apply(this,rest)) } } let eventTopic = new EventTopic() eventTopic.subscribe('book',(name)=>{ console.log(`${name}訂閱的book更新了, ${name}: 做了更新操作`) }) eventTopic.update('book','小布')
在實際項目框架中的應用,舉個例子(不了解node的,可以暫時跳過,不影響理解)
node的events 模塊:https://github.com/nodejs/node/blob/master/lib/events.js
3.總結
使用Observer模式,維護相關對象之間的關系,另一種Observer模式Pubilsh/Subscribe模式是解耦了對象。
文中例子比較粗糙,理解不准確之處,還請教正。