目录

手写发布订阅模式(手写系列二)

背景

以下是手写系列内容预告,初步计划一周一个主题。

观察者/

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})

如果觉得有用,点个赞让作者开心一下呗~

补充

饥人谷一直致力于培养有灵魂的编程者,打造专业有爱的国内前端技术圈子。如造梦师一般帮助近千名不甘寂寞的追梦人把编程梦变为现实,他们以饥人谷为起点,足迹遍布包括facebook、阿里巴巴、百度、网易、京东、今日头条、大众美团、饿了么、ofo在内的国内外大小企业。 了解培训课程:加微信 xiedaimala03,官网:https://jirengu.com