设计模式|发布-订阅模式(Publish-Subscribe Pattern)

文章目录

  • 初识发布-订阅模式
  • 发布-订阅模式的关键概念
  • 发布订阅模式的优缺点
  • 示例代码(使用 Java 实现)
  • 有哪些知名框架使用了发布-订阅模式
  • 常见面试题

初识发布-订阅模式

发布-订阅模式(Publish-Subscribe Pattern)是一种软件架构设计模式,属于行为型设计模式,用于解耦生产者(发布者)和消费者(订阅者)之间的关系。在这种模式中,发布者负责发布消息,而订阅者则可以选择订阅他们感兴趣的消息类型。当有新消息发布时,订阅者将收到通知并执行相应的操作。

发布-订阅模式的关键概念

  1. 发布者(Publisher):负责发布消息的组件。它们通常不知道谁会接收到消息,只是将消息发送给与之连接的消息队列或主题。
  2. 订阅者(Subscriber):订阅特定类型的消息,并在该类型的消息被发布时接收到通知。订阅者可以根据自己的需求选择订阅的消息类型。
  3. 消息(Message):由发布者发布并由订阅者接收的信息单元。消息可以是任何形式的数据,例如文本、JSON、XML等。
  4. 主题(Topic):定义消息类型的逻辑通道或分类。发布者将消息发布到特定的主题,而订阅者则根据需要订阅特定的主题。
  5. 消息队列(Message Queue):用于在发布者和订阅者之间传递消息的中介服务。它可以确保消息的异步传输,并提供缓冲和路由消息的功能。
  6. 事件总线(Event Bus):类似于消息队列,用于在组件之间传递消息,但通常更为轻量级,通常在单个应用程序内部使用。

发布订阅模式的优缺点

发布-订阅模式(Publish-Subscribe Pattern)具有许多优点和一些缺点:
优点:

  1. 解耦性(Decoupling): 发布-订阅模式实现了生产者和消费者之间的解耦,发布者和订阅者之间的通信通过中介(例如消息队列、事件总线)进行,彼此不直接依赖或知晓对方的存在,从而提高了系统的灵活性和可维护性。
  2. 扩展性(Scalability): 由于发布者和订阅者之间的解耦,系统可以更容易地扩展。新的发布者或订阅者可以被添加而不影响现有的组件。
  3. 灵活性(Flexibility): 发布-订阅模式允许任意数量的发布者和订阅者存在,并且支持多对多的通信。发布者和订阅者可以根据需求动态地添加、删除或修改,而不影响整个系统的运行。
  4. 异步通信(Asynchronous Communication): 由于发布者和订阅者之间的通信通常是通过消息队列或事件总线进行的,因此支持异步通信。这使得系统能够更高效地处理大量消息,并提高了响应性。
  5. 松散耦合(Loose Coupling): 发布-订阅模式降低了组件之间的耦合度,因为它们不需要直接知道彼此的存在或实现细节。这使得系统更容易理解、维护和扩展。

缺点:

  1. 消息传递顺序性难以保证(Ordering of Message Delivery): 在某些情况下,由于消息传递是异步的,发布者发布消息的顺序与订阅者接收消息的顺序可能会不一致。这可能导致一些潜在的问题,特别是对于依赖于消息顺序的场景。
  2. 调试复杂性(Debugging Complexity): 由于发布-订阅模式中的组件之间是松散耦合的,因此在调试时可能会更加复杂。当出现问题时,需要跟踪消息的传递路径以找到问题所在。
  3. 消息处理延迟(Message Processing Latency): 由于发布-订阅模式通常是异步的,消息的传递和处理可能会引入一定程度的延迟。在某些实时性要求高的应用场景中,这可能会成为一个问题。
  4. 可能引入过多的订阅者(Potential Overuse of Subscribers): 如果不加限制地使用发布-订阅模式,可能会导致系统中存在过多的订阅者,这可能会降低系统的性能和可维护性。因此,需要在设计时仔细考虑订阅者的数量和范围。

虽然发布-订阅模式具有一些缺点,但它的优点通常能够满足许多实际应用场景的需求,并且在大多数情况下,其优势远远超过了缺点。因此,在选择使用发布-订阅模式时,需要根据具体的需求和场景来权衡利弊。

示例代码(使用 Java 实现)

下面是一个简单的 Java 实现发布-订阅模式的例子:

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;// 定义事件类
class Event {private String message;public Event(String message) {this.message = message;}public String getMessage() {return message;}
}// 定义发布者类
class Publisher {private Map<String, List<Subscriber>> subscribers = new HashMap<>();// 订阅public void subscribe(String eventType, Subscriber subscriber) {subscribers.computeIfAbsent(eventType, k -> new ArrayList<>()).add(subscriber);}// 发布消息public void publish(String eventType, Event event) {List<Subscriber> subscribersList = subscribers.getOrDefault(eventType, new ArrayList<>());for (Subscriber subscriber : subscribersList) {subscriber.notify(event);}}
}// 定义订阅者接口
interface Subscriber {void notify(Event event);
}// 定义具体的订阅者类
class ConcreteSubscriber implements Subscriber {private String name;public ConcreteSubscriber(String name) {this.name = name;}@Overridepublic void notify(Event event) {System.out.println(name + " received message: " + event.getMessage());}
}public class PublishSubscribeExample {public static void main(String[] args) {Publisher publisher = new Publisher();// 创建两个订阅者Subscriber subscriber1 = new ConcreteSubscriber("Subscriber 1");Subscriber subscriber2 = new ConcreteSubscriber("Subscriber 2");// 订阅事件类型为 "news"publisher.subscribe("news", subscriber1);publisher.subscribe("news", subscriber2);// 发布事件类型为 "news" 的消息publisher.publish("news", new Event("Breaking news: COVID restrictions lifted!"));}
}

在这个例子中,首先定义了 Event 类来表示事件,然后定义了 Publisher 类作为发布者,它维护了一个映射,将事件类型与订阅者列表关联起来。Publisher 类具有 subscribe 方法用于订阅特定类型的事件,以及 publish 方法用于发布事件。

然后,定义了 Subscriber 接口,其中包含一个 notify 方法,用于在订阅者接收到消息时进行通知。ConcreteSubscriber 类实现了 Subscriber 接口,并实现了 notify 方法来处理接收到的消息。

最后,在 main 方法中,创建了一个 Publisher 对象,两个 ConcreteSubscriber 对象,并将它们订阅了事件类型为 “news” 的消息。然后,发布了一个事件类型为 “news” 的消息,所有订阅了该事件类型的订阅者都会收到通知并处理该消息。

有哪些知名框架使用了发布-订阅模式

许多知名的框架和库都采用了发布-订阅模式或者类似的事件驱动机制来解耦组件之间的通信。以下是一些常见的采用发布-订阅模式的知名框架和库:

  1. Apache Kafka:Apache Kafka 是一个分布式的流处理平台和消息队列系统,它采用了发布-订阅模式来支持大规模的消息传递。
  2. RabbitMQ:RabbitMQ 是一个开源的消息队列系统,它支持多种消息传递模式,其中包括发布-订阅模式。
  3. Redis:Redis 是一个开源的内存数据库,它提供了发布-订阅功能,允许客户端订阅多个频道或模式,并在消息发布到这些频道或模式时接收通知。
  4. Spring Framework:Spring Framework 提供了一个事件机制,通过 ApplicationEvent 和 ApplicationListener 接口,以及 @EventListener 注解,可以实现发布-订阅模式来处理应用程序中的事件。
  5. RxJava:RxJava 是一个基于观察者模式的响应式编程库,它提供了丰富的操作符和组合器,用于处理异步事件流。
  6. Vert.x:Vert.x 是一个用于构建响应式和事件驱动应用程序的工具包,它采用了发布-订阅模式来处理异步消息和事件。
  7. EventEmitter in Node.js:Node.js 中的 EventEmitter 是一个核心模块,用于实现发布-订阅模式,允许对象触发命名事件,并允许注册事件的监听器来处理这些事件。

这些框架和库都利用了发布-订阅模式的优点,如解耦、灵活性和可扩展性,从而更好地支持异步消息传递和事件处理。

常见面试题

在面试中,关于发布-订阅模式可能会涉及到多个方面的问题,包括基本概念、优点、实际应用和实现细节等。以下是一些可能会遇到的问题以及相应的答案:

  1. 发布-订阅模式的基本概念是什么?
    答案:发布-订阅模式是一种软件架构模式,用于解耦生产者(发布者)和消费者(订阅者)之间的关系。在这种模式中,发布者负责发布消息,而订阅者则可以选择订阅他们感兴趣的消息类型。
  2. 发布-订阅模式与观察者模式有何区别?
    答案:发布-订阅模式和观察者模式都用于处理对象之间的通信,但它们之间有一些区别。观察者模式中,主题(被观察者)维护了一组观察者对象,并在状态发生变化时通知它们。而在发布-订阅模式中,发布者和订阅者之间没有直接的关联,发布者将消息发布到特定的主题,而订阅者可以选择订阅他们感兴趣的主题,从而解耦了生产者和消费者。
  3. 发布-订阅模式的优点是什么?
    答案:发布-订阅模式具有以下优点:
  • 解耦性:发布者和订阅者之间没有直接的依赖关系,从而实现了解耦。
  • 灵活性:发布者和订阅者可以独立地进行扩展和修改,而不会影响到对方。
  • 可扩展性:新的发布者和订阅者可以很容易地加入到系统中,而不需要修改现有的代码。
  • 多对多通信:一个发布者可以有多个订阅者,一个订阅者也可以订阅多个发布者,实现了多对多的通信。
  1. 请举例说明一个实际应用场景中使用发布-订阅模式的情况。
    答案:一个实际应用场景是在线社交平台的消息推送功能。例如,社交平台上的用户可以选择订阅他们感兴趣的话题或其他用户的动态,而发布者则负责将新的消息发布到相应的主题上。这样一来,用户就可以接收到他们感兴趣的消息,而发布者和订阅者之间的关系是解耦的。
  2. 在实现发布-订阅模式时,有哪些关键的组件?
    答案:实现发布-订阅模式时,关键的组件包括发布者(负责发布消息)、订阅者(订阅感兴趣的消息)、消息(发布者发布的信息单元)、主题(定义消息类型的逻辑通道)、消息队列或事件总线(用于在发布者和订阅者之间传递消息的中介服务)等。
  3. 请解释发布-订阅模式的原理。
    答案: 发布-订阅模式是一种软件架构设计模式,用于解耦生产者(发布者)和消费者(订阅者)之间的关系。在这种模式中,发布者负责发布消息,而订阅者则可以选择订阅他们感兴趣的消息类型。当有新消息发布时,订阅者将收到通知并执行相应的操作,从而实现了组件之间的解耦和松耦合。
    这些问题可以帮助面试官评估候选人对发布-订阅模式的理解程度,以及其在实际应用中的应用能力。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/773239.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【python】(14)理解Python中的pypinyin库

系列文章回顾 【python】(01)初识装饰器Decorator 【python】(02)初识迭代器Iterator 【python】(03)初识生成器Generator 【python】(04)python中实现多任务并发和并行的区别 【python】(05)如何使用python中的logging模块记录日志信息 【python】(06)理解Python中的 lambda 、…

【计算机网络】IP 协议

网络层IP协议 一、认识 IP 地址二、IP 协议报头格式三、网段划分1. 初识子网划分2. 理解子网划分3. 子网掩码4. 特殊的 IP 地址5. IP 地址的数量限制6. 私有 IP 地址和公网 IP 地址7. 理解全球网络&#xff08;1&#xff09;理解公网&#xff08;2&#xff09;理解私网&#xf…

华为汽车图谱

极狐 极狐&#xff08;ARCFOX&#xff09;是由北汽、华为、戴姆勒、麦格纳等联合打造。总部位于北京蓝谷。 问界 华为与赛力斯&#xff08;东风小康&#xff09;合作的成果。 阿维塔 阿维塔&#xff08;AVATR&#xff09;是由长安汽车、华为、宁德时代三方联合打造。公司总部位…

51单片机超声波测距代码

超声波测距代码&#xff1a; #include<reg52.h>sbit echoP2^0 ; //回声接收端口 sbit trigP2^1 ;//超声波触发端口sbit wei1P2^4; sbit wei2P2^5; sbit wei3P2^6; sbit wei4P2^7;sbit inP2^2;#define dula P0 #define uchar unsigned char #define uint unsigned intlo…

代码随想录Day58:每日温度、下一个更大元素 I

每日温度 class Solution { public:vector<int> dailyTemperatures(vector<int>& temperatures) {stack<int> st;vector<int> result(temperatures.size(), 0);for(int i 0; i < temperatures.size(); i){while(!st.empty() && tempe…

数字化接口、网络身份证实名认证接口、C#实名认证接口说明示例

身份证实名认证接口是现代应用程序中的越来越重要的一部分&#xff0c;通过身份证识别接口来实现身份信息的提取与录入&#xff0c;实名认证接口通过核验身份证二要素、三要素的方式实时联网进行身份信息的真伪核验。 网民在进行网络活动时&#xff0c;均需要用户提供真实身份…

软考高级:常见中间件分类和例题

作者&#xff1a;明明如月学长&#xff0c; CSDN 博客专家&#xff0c;大厂高级 Java 工程师&#xff0c;《性能优化方法论》作者、《解锁大厂思维&#xff1a;剖析《阿里巴巴Java开发手册》》、《再学经典&#xff1a;《Effective Java》独家解析》专栏作者。 热门文章推荐&am…

canal: 连接kafka (docker)

一、确保mysql binlog开启并使用ROW作为日志格式 docker 启动mysql 5.7配置文件 my.cnf [mysqld] log-binmysql-bin # 开启 binlog binlog-formatROW # 选择 ROW 模式 server-id1一定要确保上述两个值一个为ROW&#xff0c;一个为ON 二、下载canal的run.sh https://github.c…

一周学会Django5 Python Web开发-Django5模型定义

锋哥原创的Python Web开发 Django5视频教程&#xff1a; 2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 Django5 Python web开发 视频教程(无废话版) 玩命更新中~共计41条视频&#xff0c;包括&#xff1a;2024版 Django5 Python we…

C语言实现:变位词程序拓展问题

开篇 今天的问题&#xff0c;是在之前变位词程序的基础上&#xff0c;进行了一些拓展。问题来源于《编程珠玑》第2章&#xff0c;课后习题1。 问题概要 考虑查找给定输入单词的所有变位词问题&#xff0c;仅给定单词和字典的情况下&#xff0c;如何解决该问题&#xff1f;如果有…

26. BI - PageRank 拓展以及如何利用 networkx 来分析希拉里丑闻

本文为 「茶桁的 AI 秘籍 - BI 篇 第 26 篇」 Hi, 我是茶桁. 上节课咱们讲解了 PageRank 的两种模型, 并分别做了代码上的演示. 这节课, 让我们来看看 PageRank 的影响力及其应用. PageRank 已经超越了原来提出来的模型, 因为 PageRank 的影响力影响到了后续很多的一些模型, …

【疑惑】-谷歌是如何获取数据的

搜索引擎爬虫&#xff1a; 谷歌的搜索引擎通过爬虫程序在互联网上爬取和收集网页信息。这些爬虫会遵循特点的算法和规则&#xff0c;访问内容&#xff0c;并且提取出关键信息 用户的搜索行为&#xff1a; 当用户使用谷歌搜索引擎进行搜索的时候&#xff0c;谷歌会收集分析用户…

【前端学习——js篇】7.函数缓存

具体见&#xff1a;https://github.com/febobo/web-interview 7.函数缓存 函数缓存&#xff0c;就是将函数运算过的结果进行缓存 本质上就是用空间&#xff08;缓存存储&#xff09;换时间&#xff08;计算过程&#xff09; 常用于缓存数据计算结果和缓存对象。 其实现主要…

Code Review(代码审查)

代码审查是软件开发生命周期的重要组成部分。它能显著提高开发人员的代码质量。 这个过程就像写一本书。作者写好了内容&#xff0c;出版社编辑对其进行了校审&#xff0c;所以没有出现任何错误&#xff0c;例如将“你”与“你的”混淆。这个案例中&#xff0c;代码审查是阅读…

Linux reboot命令教程:如何安全地重启你的Linux系统(附实例详解和注意事项)

Linux reboot命令介绍 reboot命令用于重新启动你的Linux系统。当你的系统内核更新时&#xff0c;除非你正在使用Livepatch或KernelCare&#xff0c;否则你需要重启你的Linux系统。在其他情况下&#xff0c;例如解决硬件问题、安装应用程序等&#xff0c;也可能需要重新启动系统…

我的创作纪念日 ---- 2024/3/26

前言 2024.3.26是我在CSDN成为创作者的第128天&#xff0c;也是我第一次真正在网上创作的第128天 当我还在日常创作时&#xff0c;突然发现我收到了一封信 我想我可以分享一下这段时间的感想以及收获 机缘 在CSDN的这段时间里&#xff0c;我学习到了很多知识&#xff0c;也…

数据结构——链表(单链表)

大家好&#xff0c;又是我&#xff08;小锋&#xff09;&#xff0c;今天给大家带了一个比较有挑战的章节&#xff08;链表&#xff09;&#xff0c;但是不用担心&#xff0c;小锋会陪大家一起度过。 顺序表的思考与问题 1. 中间/头部的插入删除&#xff0c;时间复杂度为O(N) …

【python】flask模板渲染引擎Jinja2,通过后端数据渲染前端页面

✨✨ 欢迎大家来到景天科技苑✨✨ &#x1f388;&#x1f388; 养成好习惯&#xff0c;先赞后看哦~&#x1f388;&#x1f388; &#x1f3c6; 作者简介&#xff1a;景天科技苑 &#x1f3c6;《头衔》&#xff1a;大厂架构师&#xff0c;华为云开发者社区专家博主&#xff0c;…

Spring Cloud 八:微服务架构中的数据管理

Spring Cloud 一&#xff1a;Spring Cloud 简介 Spring Cloud 二&#xff1a;核心组件解析 Spring Cloud 三&#xff1a;API网关深入探索与实战应用 Spring Cloud 四&#xff1a;微服务治理与安全 Spring Cloud 五&#xff1a;Spring Cloud与持续集成/持续部署&#xff08;CI/C…

Eladmin-jpa基于SpringBoot和Vue的前后端分离后台管理系统​

在当今快速发展的软件开发领域&#xff0c;前后端分离的架构模式已经成为主流。这种架构模式不仅可以提高开发效率&#xff0c;还能使系统更加易于维护和扩展。Eladmin-jpa是一个基于Spring Boot 2.6.4、Spring Boot Jpa、JWT、Spring Security、Redis和Vue的前后端分离的后台管…