手写发布-订阅模式

简介: 发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

一、 什么是发布-订阅模式

1. 定义

发布-订阅模式其实是一种对象间一对多的依赖关系,当一个对象的状态发送改变时,所有依赖于它的对象都将得到状态改变的通知。

订阅者(Subscriber)把自己想订阅的事件注册(Subscribe)到调度中心(Event Channel),当发布者(Publisher)发布该事件(Publish Event)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event)订阅者注册到调度中心的处理代码。

2. 例子

我们关注的公众号文章,给我们进行推送时候,即是发布订阅模式

公众号属于发布者,我们属于订阅者

用户将订阅公众号的事件注册到调度中心,公众号作为发布者,当有新文章发布时,公众号发布该事件到调度中心,调度中心会及时发消息告知用户。

二、 如何实现发布-订阅模式?

1. 实现思路

  • 创建一个对象
  • 在该对象上创建一个调度中心
  • on 方法用来把函数 fn 都加到缓存列表中(订阅者注册事件到调度中心)
  • emit 方法取到 arguments 里第一个当做 event,根据 event 值去执行对应缓存列表中的函数(发布者发布事件到调度中心,调度中心处理代码)
  • off 方法可以根据 event 值取消订阅(取消订阅)
  • once 方法只监听一次,调用完毕后删除缓存函数(订阅一次)

2. 代码

// 公众号调度中心
class EventHub {
  constructor(){
    // 缓存列表,存放 event 及 fn
    this.map = {};
  }
  on(event, fn) {
     // 如果对象中没有对应的 event 值,也就是说明没有订阅过,就给 event 创建个缓存列表
    this.map[event] = this.map[event] || []
    // 把 fn 添加到对应 event 的缓存列表里
    this.map[event].push(fn)
  }
  emit(event, data) {
    const fnList = this.map[event] || []
    // 如果缓存列表里没有 fn 就return
    if (!fnList || fnList.length === 0) return;
    // 遍历 event 值对应的缓存列表,依次执行 fn
    fnList.forEach(fn => fn.call(undefined, data))
  }
  off(event, fn) {
    const fnList = this.map[event] || []
    const index = fnList.indexOf(fn)
    // 如果缓存列表里没有要找的fn 就return
    if(index < 0) return
    fnList.splice(index, 1)
  }
  //执行一次
  once(event, callback){
    const f = (data) => {
      callback(data);    
      this.off(event, f);
    }
    this.on(event, f);
  }
}
function user1 (content) {
    console.log('用户1订阅了:', content);
};
function user2 (content) {
    console.log('用户2订阅了:', content);
};
function user3 (content) {
    console.log('用户3订阅了:', content);
}
function user4 (content) {
    console.log('用户4订阅了:', content);
}
const e = new EventHub()
// 订阅
e.on('article1', user1);
e.on('article1', user2);
e.on('article1', user3);
// 取消user2方法的订阅
e.off('article1', user2);
e.once('article2', user4)
// 发布
e.emit('article1', 'Javascript 发布-订阅模式');
e.emit('article1', 'Javascript 发布-订阅模式');
e.emit('article2', 'Javascript 观察者模式');
e.emit('article2', 'Javascript 观察者模式');
/*
    用户1订阅了: Javascript 发布-订阅模式
    用户3订阅了: Javascript 发布-订阅模式
    用户1订阅了: Javascript 发布-订阅模式
    用户3订阅了: Javascript 发布-订阅模式
    用户4订阅了: Javascript 观察者模式
*/

三、 总结

1. 优点

  • 对象之间解耦
  • 异步编程中,可以更松耦合的代码编写

2. 缺点

  • 创建订阅者本身要消耗一定的时间和内存
  • 虽然可以弱化对象之间的联系,多个发布者和订阅者嵌套一起的时候,程序难以跟踪维护



目录
相关文章
|
29天前
|
设计模式 消息中间件 安全
C# 一分钟浅谈:观察者模式与订阅发布模式
【10月更文挑战第11天】本文介绍了观察者模式和订阅发布模式,这两种设计模式主要用于实现对象间的解耦。观察者模式通过事件和委托实现一个对象状态改变时通知多个依赖对象;订阅发布模式则通过事件聚合器实现发布者与订阅者之间的解耦。文章详细探讨了这两种模式的实现方式、常见问题及避免方法,帮助开发者在实际项目中更好地应用这些模式,提升代码的可维护性和扩展性。
56 1
|
4月前
|
消息中间件 中间件 Kafka
中间件发布/订阅模型
【7月更文挑战第9天】
54 1
中间件发布/订阅模型
|
5月前
|
消息中间件 NoSQL 中间件
中间件发布与订阅模型
【6月更文挑战第21天】
41 1
|
5月前
|
存储 负载均衡 安全
中间件消息发布-订阅模式
【6月更文挑战第9天】
114 5
|
传感器 负载均衡 物联网
MQTT v5共享订阅是怎么回事?如何使用共享订阅提高消息订阅的灵活性和可伸缩性?
MQTT v5共享订阅是怎么回事?如何使用共享订阅提高消息订阅的灵活性和可伸缩性?
477 1
|
设计模式 Go
Go语言事件系统设计解析:发布-订阅模式实战
Go语言事件系统设计解析:发布-订阅模式实战
461 0
|
6月前
|
移动开发 小程序 Go
【社区每周】小程序消息订阅插件升级为消息订阅接口(2022年8月第五期)
【社区每周】小程序消息订阅插件升级为消息订阅接口(2022年8月第五期)
42 0
|
前端开发
前端学习案例1-发布订阅者模式1
前端学习案例1-发布订阅者模式1
73 0
前端学习案例1-发布订阅者模式1
|
前端开发
前端学习案例2-发布订阅者模式2
前端学习案例2-发布订阅者模式2
71 0
前端学习案例2-发布订阅者模式2
|
前端开发
前端学习案例2-发布订阅者模式2
前端学习案例2-发布订阅者模式2
72 0
前端学习案例2-发布订阅者模式2