美文网首页
超简单发布订阅模式讲解

超简单发布订阅模式讲解

作者: 码农说 | 来源:发表于2023-10-11 20:54 被阅读0次

    发布订阅模式

    发布订阅模式和观察者模式是两种常见的设计模式,用于处理事件和通信。在本文中,我们将逐步构建一个功能完善的EventEmitter,并通过这一过程来深入理解发布订阅模式。

    简洁的版本

    我们构建一个简单的发布订阅模型:

    class EventEmitter {
      constructor() {
        this.events = {};
      }
    
      // 订阅事件
      on(event, listener) {
        if (!this.events[event]) {
          this.events[event] = [];
        }
        this.events[event].push(listener);
      }
    
      // 卸载事件
      off(event, listener) {
        if (this.events[event]) {
          this.events[event] = this.events[event].filter(l => l !== listener);
        }
      }
    
      // 发布事件
      emit(event, data) {
        if (this.events[event]) {
          this.events[event].forEach(listener => listener(data));
        }
      }
    }
    

    我们创建了一个EventEmitter类,其中包括了onoffemit方法,分别用于订阅事件、卸载事件和发布事件。

    代码流程解释:

    • on(event, listener): 该函数用于订阅事件。如果事件列表中不存在特定事件,我们会创建一个新的事件数组,然后将传入的监听器添加到该数组中。
    • off(event, listener): 这个函数用于卸载事件。我们首先检查事件列表是否包含特定事件,如果是,则使用 filter 方法将传入的监听器从事件数组中移除。
    • emit(event, data): 该函数用于发布事件。如果事件列表包含特定事件,我们将遍历事件数组并触发每个监听器,传递事件数据。

    升级版:添加一次性调用

    我们引入了一次性订阅,也就是once方法。

    // ...
    
      // 一次性订阅
      once(event, listener) {
        const onceWrapper = data => {
          listener(data);
          this.off(event, onceWrapper);
        };
        this.on(event, onceWrapper);
      }
    

    流程解释:

    • once(event, listener): 这个函数允许你一次性订阅事件,即事件触发一次后自动卸载订阅。它内部创建了一个包装函数 onceWrapper,该函数会在事件触发时执行一次性监听器,然后自动卸载订阅,以确保监听器只会执行一次。

    进阶版:支持连续调用

    让我们的EventEmitter支持连续调用,这样我们可以在一个链中连续执行多个方法。

    class EventEmitter {
      // ...
    
      // 订阅事件,支持连续调用
      on(event, listener) {
        if (!this.events[event]) {
          this.events[event] = [];
        }
        this.events[event].push(listener);
        return this;
      }
    
      // 卸载事件,支持连续调用
      off(event, listener) {
        if (this.events[event]) {
          this.events[event] = this.events[event].filter(l => l !== listener);
        }
        return this;
      }
    
      // 一次性订阅,支持连续调用
      once(event, listener) {
        const onceWrapper = data => {
          listener(data);
          this.off(event, onceWrapper);
        };
        this.on(event, onceWrapper);
        return this;
      }
    }
    

    流程解释:

    • on(event, listener), off(event, listener), once(event, listener): 在这一步,我们添加了 return this; 语句,这意味着每个方法调用后都会返回EventEmitter实例。这允许我们在一个链式调用中连续调用不同的方法,从而提高了代码的可读性。

    这三个函数的返回使得我们可以像下面这样连续调用它们:

    eventEmitter
      .on('event1', listener1)
      .on('event2', listener2)
      .once('event3', listener3)
      .off('event4', listener4);
    

    通过连续调用,我们可以在一个链中轻松执行多个操作。

    完整版:添加事件缓存

    在第四步中,我们引入了事件缓存,允许查看已经订阅的事件。

    // ...
    
      // 获取事件列表
      getEvents() {
        return Object.keys(this.events);
      }
    }
    

    代码流程解释:

    • getEvents(): 这个函数允许你获取已订阅事件的列表。它返回一个数组,包含了所有已经订阅的事件名称。

    发布订阅模式与观察者模式区别

    主要区别:

    • 发布订阅模式更加灵活,允许多个发布者和订阅者之间的多对多关系,发布者不需要了解订阅者的存在。它通常使用一个中介来处理事件分发。
    • 观察者模式通常是一对多关系,一个主题对象可以有多个观察者,但观察者的接口是明确定义的。主题对象需要维护观察者列表,并在状态变化时通知观察者。

    观察者模式示例:

    // 主题
    class Subject {
      constructor() {
        this.observers = [];
      }
    
      addObserver(observer) {
        this.observers.push(observer);
      }
    
      removeObserver(observer) {
        const index = this.observers.indexOf(observer);
        if (index !== -1) {
          this.observers.splice(index, 1);
        }
      }
    
      notify(message) {
        this.observers.forEach(observer => observer.update(message));
      }
    }
    
    // 观察者
    class Observer {
      update(message) {
        console.log(`Received message: ${message}`);
      }
    }
    
    const subject = new Subject();
    const observer1 = new Observer();
    const observer2 = new Observer();
    
    subject.addObserver(observer1);
    subject.addObserver(observer2);
    subject.notify("Hello, observers!");
    

    在我们上面的介绍中,发布订阅模式使用了中介者来处理事件的发布和订阅,而观察者模式是一对多的关系,主题对象直接通知观察者。

    总结

    通过逐步构建一个支持连续调用的事件模型,我们介绍了基本的发布订阅模式。同时也简单介绍了发布订阅模式和观察者模式之间差异。发布订阅模式更加灵活,支持多对多关系,适用于更多的场景,而观察者模式是一对多关系,明确定义了观察者的接口。最后希望本文对大家理解发布订阅模式有帮助。

    相关文章

      网友评论

          本文标题:超简单发布订阅模式讲解

          本文链接:https://www.haomeiwen.com/subject/uirnbdtx.html