站点工具

用户工具


手写观察者/发布订阅模式

Subject是构造函数,new Subject() 创建一个主题对象,该对象内部维护订阅当前主题的观察者数组。主题对象上有一些方法,如添加观察者(addObserver)、删除观察者(removeObserver)、通知观察者更新(notify)。 当notify 时实际上调用全部观察者 observer 自身的 update 方法。

Observer 是构造函数,new Observer() 创建一个观察者对象,该对象有一个 update 方法,观察者可以订阅主题,实际上是把自己加入到主题的订阅者列表里。

class Subject {
  observers = []
 
  addObserver(observer) {
    this.observers.push(observer)
  }
  removeObserver(observer) {
    let index = this.observers.indexOf(observer)
    if(index > -1){
      this.observers.splice(index, 1)
    }
  }
  notify() {
    this.observers.forEach(observer => {
      observer.update()
    })
  }
}
 
 
class Observer{
  update() {}
  subscribeTo(subject) {
    subject.addObserver(this)
  }
} 

测试代码

let subject = new Subject()
let observer = new Observer()
observer.update = function() {
  console.log('observer update')
}
observer.subscribeTo(subject)  //观察者订阅主题
 
subject.notify()

手写一个EventBus

观察者模式和发布订阅模式具体的写法和区别没有官方的定义,下面这种写法反而更常见。

class EventBus {
  map = {} 
 
  on(type, handler) {
    this.map[type] = (this.map[type] || []).concat(handler)
  }
 
  fire(type, data) {
    this.map[type] && this.map[type].forEach(handler => handler(data))
  }
 
  off(type, handler) {
    if(this.map[type]) {
      if(!handler) {
        delete this.map[type]
      } else {
        let index = this.map[type].indexOf(handler)
        this.map[type].splice(index, 1)
      }
    }
  }
}

测试代码

const eventBus = new EventBus()
 
eventBus.on('click:btn', data => {
  console.log(data)
})
 
eventBus.fire('click:btn', {a: 1, b: 2})
eventBus.off('click:btn')
eventBus.fire('click:btn', {a: 1, b: 2})
若愚 · 2021/09/27 11:46 · javascript_发布订阅.txt