js类实现发布订阅者模式

271 阅读2分钟
1.概述
  • 发布订阅者模式本质是对象间一对多的依赖关系,当一个对象发生改变时,所有依赖它的对象都会收到改变通知。
  • 发布订阅者模式,是设计模式中最常见的一种模式,也是前端用的最多的一种模式。在前端各大框架中都会听到它的存在。
  • 网上传最多的图基本都是以下这种结构,一目了然。

发布-订阅者模式.drawio.png

  • 然后我从代码实现层面,也画了个发布订阅者模式,一个简易的发布订阅,订阅事件on()其实就是往Map()里存储订阅的事件;发布emit()其实就是根据key值拿出事件,挨个的执行一遍。

发布订阅原理图.drawio.png

2.实现一个简易的发布订阅者模式
  • 创建一个list用来存储订阅的事件
class EventCenter {
  // 调度中心
  constructor() {
    this.list = new Map();
  }
}
  • 订阅事件,往缓存列表list中push数据
  // 订阅
  on(event, fn) {
    // 如果list中没有对应的 event 值,也就是说明没有订阅过,就给 event 创建个缓存列表
    if (!this.list.get(event)) {
      this.list.set(event, []);
    }
    // 如有list中有相应的 event 值,把 fn 添加到对应 event 的缓存列表里
    this.list.get(event).push(fn);
    console.log("我被订阅了");
  }
  • 发布事件,发布事件其实就是根据event值,找到存储的事件,然后挨个的执行一遍。
  // 发布
  emit(event, ...value) {
    // 取出event中的值,若没有则为[]
    if (this.list.get(event).length <= 0) {
      return false;
    }
    let fnList = this.list.get(event);
    // 遍历event对应的缓存列表,依次执行fn
    fnList.forEach((fn) => {
      fn(...value);
    });
  }
  • 取消订阅事件,将事件从缓存列表中清除。
  // 取消订阅,从调度中心中删除对应的事件
  off(event, fn) {
    // 如果list中没有对应的event值,那就说明没有订阅过
    if (!this.list.get(event)) {
      console.log("没有订阅过该事件");
      return false;
    }
    // 取出event中订阅的事件,若没有则为[]
    if (this.list.get(event).length <= 0) {
      return false;
    }
    let fnList = this.list.get(event);
    fnList.forEach((item, index) => {
      if (item === fn) {
        fnList.splice(index, 1);
        console.log("成功取消订阅");
      }
    });
  }
  • 最后实现一个小的案例。
export default function SubPub() {
    console.log('发布订阅者对象', eventCenter);
    const f1 = (name) => {
        console.log('订阅了1', name);
    }
    const f2 = (name) => {
        console.log('订阅了2', name);
    }
    const f3 = (name) => {
        console.log('订阅了3', name);
    }
    return (
        <div>
            <button onClick={() => { eventCenter.on('event', f1) }}>订阅1</button>
            <button onClick={() => { eventCenter.on('event2', f2) }}>订阅2</button>
            <button onClick={() => { eventCenter.on('event3', f3) }}>订阅3</button>
            <button onClick={() => { eventCenter.emit('event', 'wo') }}>发布1</button>
            <button onClick={() => { eventCenter.emit('event2', 'wo') }}>发布2</button>
            <button onClick={() => { eventCenter.emit('event3', 'wo') }}>发布3</button>
            <button onClick={() => { eventCenter.off('event', f1)}}>取消订阅1</button>
        </div>
    );
}

image_0.005161194120991697.gif

3.利用发布订阅者模式实现react组件间的传值,未完待续...