JavaScript设计模式(四):发布-订阅模式、观察者模式

定义

我们暂且把发布订阅模式和观察者模式理解成相同的,是行为型模式的一种,定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态变化时,会通知所有的观察者对象,使他们能够自动更新自己。
在日常生活中也有例子,例如我们办理银行卡时,如果订阅了手机短信功能,那么每次消费后都会给我们发送短信。

简单实现

我们先来简单模拟实现一个发布订阅模式。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
const observer = (function () {
const listeners = [];
// 订阅事件
function subscribe (sub) {
listeners.push(sub);
}
// 发布通知
function notify(message) {
listeners.forEach(item => item(message));
}
return {
subscribe,
notify,
};
})()

observer.subscribe(function (message) {
console.log("我订阅了了消息", message)
})

observer.notify('发布了一条信息。。。')

以上代码通过 listeners 存放订阅信息,subscribe 方法来订阅信息,notify 方法来发布信息。

应用

EventBus

EventBus 就是基于发布-订阅模式实现的,由三个主要元素构成,事件、发布者、订阅者。
实现一个简易的 EventBus 需要几个关键因素

  1. 定义一个 tasks 来管理事件
  2. on 方法来订阅事件
  3. off 方法来退订
  4. once 方法只订阅一次
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    class EventBus {
    constructor() {
    // 初始化一个 tasks 存放事件名和对应的事件
    this.tasks = {};
    }
    // 订阅事件
    on(type, event) {
    // 第一次订阅前先初始化
    if (!this.tasks[type]) {
    this.tasks[type] = [];
    }
    this.tasks[type].push(event);
    }
    // 发布
    emit(type, ...rest) {
    if (!this.tasks[type]) return;
    // 循环执行所有回调
    this.tasks[type].forEach(event => event(...rest));
    }
    // 取消订阅
    off(type, event) {
    if (!this.tasks[type]) return;
    // 找到对应索引进行删除
    const index = this.tasks[type].indexOf(event);
    if (index !== -1){
    this.tasks[type].splice(index, 1);
    }
    }
    // 单次注册 执行完一次需要销毁
    once(type, event) {
    const that = this;
    // 对原方法包装一下 在 _once 方法内执行 event 执行完就删除 订阅用的也是 _once 方法
    function _once(...rest) {
    event.apply(...arguments);
    that.off(type, _once);
    }
    this.on(type, _once);
    }
    }

    const tasks = new EventBus();

    tasks.once('sayHello', () => console.log("Hello World"))
    tasks.on('sayYes', ()=> console.log('yes'))

    tasks.emit('sayHello')
    tasks.emit('sayYes')

Redux

我们常用的状态管理工具 Redux 中就使用到了观察者模式,使用 subscribe 进行订阅,dispatch 进行发布。

发布订阅模式和观察者模式的区别

一句话简单解释就是发布订阅模式需要一个中间商,观察者模式不需要,形象化解释就是小组都需要一个文件,观察者模式就是领导直接把文件发送给你,发布订阅模式就是领导把文件放在某个公有文件夹中你自己去下载。另外如果是观察者模式,那么可能把所有文件都发给了你,而发布订阅模式,你就可以按需选择你用到的文件下载即可。

小结

发布-订阅模式应用的比较广泛,他帮助我们对模块间进行解耦,但同时也会会消耗空间内存,当你订阅了事件但从未触发,这个事件依旧占用着内存,造成浪费,所以合理使用也很重要。


JavaScript设计模式(四):发布-订阅模式、观察者模式
https://l1ushun.github.io/2023/10/13/design-observer/
作者
liu shun
发布于
2023年10月13日