深入理解与手写发布订阅模式

🤍 前端开发工程师、技术日更博主、已过CET6

🍨 阿珊和她的猫_CSDN博客专家、23年度博客之星前端领域TOP1

🕠 牛客 高级专题作者、打造专栏《前端面试必备》《2024面试高频手撕题》《前端求职突破计划》

🍚 蓝桥云课 签约作者、上架课程《Vue.js 和 Egg.js 开发企业级健康管理项目》《带你从入门到实战全面掌握 uni-app》

文章目录

引言

在软件开发领域,发布订阅模式(Publish-Subscribe Pattern)是一种广泛应用的设计模式,它在解耦组件之间的依赖关系、实现事件驱动的编程方面发挥着重要作用。通过这种模式,不同的组件可以在不直接依赖对方的情况下进行通信和交互,从而提高系统的可维护性和扩展性。本文将详细介绍发布订阅模式的概念、原理,并通过手写代码来深入理解其实现过程。

发布订阅模式的基本概念

发布订阅模式包含三个主要角色:发布者(Publisher)、订阅者(Subscriber)和事件中心(Event Center)。

  • 发布者:负责产生事件,并将事件发布到事件中心。它并不关心哪些订阅者会处理这些事件。
  • 订阅者:向事件中心订阅特定类型的事件,当该类型的事件被发布时,订阅者会接收到通知并执行相应的处理逻辑。
  • 事件中心:作为发布者和订阅者之间的中介,它维护着事件与订阅者之间的映射关系,当接收到发布者发布的事件时,会将事件通知给所有订阅了该事件的订阅者。

手写发布订阅模式的实现步骤

1. 定义事件中心类

首先,我们需要定义一个事件中心类,用于管理事件和订阅者。

javascript 复制代码
class EventEmitter {
    constructor() {
        // 使用对象存储事件和对应的订阅者数组
        this.events = {};
    }
}

在上述代码中,我们创建了一个 EventEmitter 类,其构造函数初始化了一个空的 events 对象,用于存储不同事件类型及其对应的订阅者数组。

2. 实现订阅方法(on

接下来,我们为事件中心类添加一个 on 方法,用于订阅事件。

javascript 复制代码
class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(eventName, callback) {
        // 如果事件不存在,则初始化一个空数组来存储订阅者
        if (!this.events[eventName]) {
            this.events[eventName] = [];
        }
        // 将回调函数添加到对应事件的订阅者数组中
        this.events[eventName].push(callback);
        return this;
    }
}

on 方法接收事件名称 eventName 和回调函数 callback 作为参数。如果该事件名称在 events 对象中不存在,则创建一个空数组。然后将回调函数添加到对应事件的订阅者数组中,并返回 this,以便支持链式调用。

3. 实现发布方法(emit

然后,实现 emit 方法,用于发布事件。

javascript 复制代码
class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(eventName, callback) {
        if (!this.events[eventName]) {
            this.events[eventName] = [];
        }
        this.events[eventName].push(callback);
        return this;
    }

    emit(eventName, ...args) {
        // 获取对应事件的订阅者数组
        const callbacks = this.events[eventName];
        if (callbacks && callbacks.length > 0) {
            // 依次执行每个订阅者的回调函数,并传递参数
            callbacks.forEach(callback => callback(...args));
        }
        return this;
    }
}

emit 方法接收事件名称 eventName 和任意数量的参数 ...args。它首先获取对应事件的订阅者数组,如果数组存在且不为空,则遍历数组并依次执行每个订阅者的回调函数,同时将参数传递给回调函数。

4. 实现取消订阅方法(off

为了使订阅者能够取消订阅事件,我们还需要实现一个 off 方法。

javascript 复制代码
class EventEmitter {
    constructor() {
        this.events = {};
    }

    on(eventName, callback) {
        if (!this.events[eventName]) {
            this.events[eventName] = [];
        }
        this.events[eventName].push(callback);
        return this;
    }

    emit(eventName, ...args) {
        const callbacks = this.events[eventName];
        if (callbacks && callbacks.length > 0) {
            callbacks.forEach(callback => callback(...args));
        }
        return this;
    }

    off(eventName, callback) {
        const callbacks = this.events[eventName];
        if (callbacks) {
            // 找到并删除对应的回调函数
            const index = callbacks.indexOf(callback);
            if (index!== -1) {
                callbacks.splice(index, 1);
            }
        }
        return this;
    }
}

off 方法接收事件名称 eventName 和要取消订阅的回调函数 callback。它先获取对应事件的订阅者数组,然后在数组中查找回调函数的索引,如果找到则使用 splice 方法将其从数组中删除。

使用示例

javascript 复制代码
// 创建事件中心实例
const emitter = new EventEmitter();

// 订阅事件
const callback1 = function(data) {
    console.log('Callback 1:', data);
};
emitter.on('event1', callback1);

// 发布事件
emitter.emit('event1', 'Hello, World!');

// 取消订阅
emitter.off('event1', callback1);

// 再次发布事件,已取消订阅的回调函数不会被执行
emitter.emit('event1', 'Another message');

在上述示例中,我们首先创建了一个 EventEmitter 实例 emitter,然后订阅了一个名为 event1 的事件,并定义了一个回调函数 callback1。接着发布了 event1 事件,回调函数被执行并输出相应信息。之后取消了对 event1 事件的订阅,再次发布 event1 事件时,已取消订阅的回调函数不再被执行。

总结

通过手写实现发布订阅模式,我们深入理解了其核心原理和实现细节。发布订阅模式通过事件中心有效地解耦了发布者和订阅者之间的依赖关系,使得系统更加灵活和可扩展。在实际开发中,这种模式广泛应用于各种场景,如前端框架中的事件系统、后端服务之间的通信等。掌握发布订阅模式,有助于我们编写更加健壮和高效的软件系统。

相关推荐
懷淰メ3 小时前
python3GUI--模仿百度网盘的本地文件管理器 By:PyQt5(详细分享)
开发语言·python·pyqt·文件管理·百度云·百度网盘·ui设计
yinuo3 小时前
一行 CSS 就能搞定!用 writing-mode 轻松实现文字竖排
前端
新子y3 小时前
【小白笔记】普通二叉树(General Binary Tree)和二叉搜索树的最近公共祖先(LCA)
开发语言·笔记·python
重整旗鼓~3 小时前
28.redisson源码分析分布式锁
java·开发语言
哼?~3 小时前
C++11标准 上 (万字解析)
开发语言·c++
snow@li3 小时前
html5:拖放 / demo / 拖放事件(Drag Events)/ DataTransfer 对象方法
前端·html·拖放
爱看书的小沐3 小时前
【小沐杂货铺】基于Three.js渲染三维风力发电机(WebGL、vue、react、WindTurbine)
javascript·vue.js·webgl·three.js·opengl·风力发电机·windturbine
VB.Net4 小时前
C#循序渐进
开发语言·c#
楼田莉子4 小时前
C++学习:C++11扩展:constexpr特性
开发语言·c++·学习