發布-訂閱模式,簡單了解


發布-訂閱模式,簡單了解。

  • 觀察者模式(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模式是解耦了對象。

文中例子比較粗糙,理解不准確之處,還請教正。

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM