js 中的观察者模式 & 发布订阅模式

578 阅读2分钟

前言

观察者模式和发布订阅模式是两种设计模式,可以基于多种设计模式设计架构模式。

观察者模式

观察者模式有两个角色,观察者 & 被观察者。

例子1:拍卖师报价。拍卖师就是被观察者,观众和竞拍者就是观察者。

例子2:报纸期刊的订阅。报社就是被观察者,订报的人就是观察者

观察者模式定义了一种一对多的情况,当这个一发生变化,这些多都会得到通知

// 被观察者
class Dep {
  constructor() {
    this.watchers = [] // 观察者列表,通知的时候要用
  }

  // 添加观察者
  addWatcher(watcher) {
    this.watchers.push(watcher)
  }

  // 通知所有观察者
  notify() {
    this.watchers.forEach(watcher => {
      watcher.update()
    })
  }
}

// 观察者
class Watcher {
  constructor(callback) {
    this.callback = callback
  }

  update() {
    this.callback()
  }
}

// 创建被观察者
const dep = new Dep()

// 创建观察者 1,2
const watcher1 = new Watcher(() => console.log('1'))
const watcher2 = new Watcher(() => console.log('2'))

// 将观察者加入到被观察者上
dep.addWatcher(watcher1)
dep.addWatcher(watcher2)

// 要发新通知了
dep.notify()

setTimeout(() => {
  dep.notify()
}, 2000)

当观察者加入监听之后就会接收到被观察者发出的通知。代码形式可以变化,并不一定要按照上面的方式

✅ 整理出观察者和被观察者的逻辑,进行解耦

❌ 所有的观察者都收到信息,不能自定义

发布订阅模式

发布订阅模式有三个角色,发布者 & 订阅者 & 事件中心。例子:网友通过淘宝买东西。网友是订阅者,商家是发布者,物流则是事件中心

将每个订阅者独立看待,把订阅者的回调函数放置到事件中心存放。

class PubSub {
  constructor() {
    this.list = []
  }

  // 订阅
  subscribe(key, fn) {
    this.list.push({
      key,
      fn
    })
  }

  // 发布
  publish(key) {
    for (let i = 0; i < this.list.length; i++) {
      if (key === this.list[i].key) {
        this.list[i].fn()
        break
      }
    }
  }

  // 取消订阅
  unSubscribe() { }
}

const pub = new PubSub()

pub.subscribe('s1', () => {
  console.log('s1')
})

pub.subscribe('s2', () => {
  console.log('s2')
})

pub.publish('s2')

setTimeout(() => {
  pub.publish('s1')
}, 2000)

可以自定义发布订阅者

小结

  1. 观察者模式是一个目标对多个观察者,当目标发生改变,通知所有的观察者
  2. 发布订阅模式基于观察者模式上添加了事件中心做调度作用。可以自定义发布订阅者
  3. 两种模式都是抽离观察者和被观察者做到解耦的目的