当前位置: 首页 > news >正文

设计模式|发布-订阅模式(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. 请解释发布-订阅模式的原理。
    答案: 发布-订阅模式是一种软件架构设计模式,用于解耦生产者(发布者)和消费者(订阅者)之间的关系。在这种模式中,发布者负责发布消息,而订阅者则可以选择订阅他们感兴趣的消息类型。当有新消息发布时,订阅者将收到通知并执行相应的操作,从而实现了组件之间的解耦和松耦合。
    这些问题可以帮助面试官评估候选人对发布-订阅模式的理解程度,以及其在实际应用中的应用能力。

相关文章:

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

文章目录 初识发布-订阅模式发布-订阅模式的关键概念发布订阅模式的优缺点示例代码&#xff08;使用 Java 实现&#xff09;有哪些知名框架使用了发布-订阅模式常见面试题 初识发布-订阅模式 发布-订阅模式&#xff08;Publish-Subscribe Pattern&#xff09;是一种软件架构设…...

根据疾病名生成病例prompt

prompt 请根据疾病名&#xff1a;" disease_name " 为我生成一份病历。下面是病历内容的要求&#xff1a;病例应严格包含如下几项: 性别&#xff0c;年龄&#xff0c;疾病名&#xff08;必须是" disease_name "&#xff09;&#xff0c;主诉&#xff…...

HarmonyOS网格布局:List组件和Grid组件的使用

简介 在我们常用的手机应用中&#xff0c;经常会见到一些数据列表&#xff0c;如设置页面、通讯录、商品列表等。下图中两个页面都包含列表&#xff0c;“首页”页面中包含两个网格布局&#xff0c;“商城”页面中包含一个商品列表。 上图中的列表中都包含一系列相同宽度的列表…...

NASA数据集—— 1984-2019年湖泊生长季绿色表面反射率趋势数据集

ABoVE: Lake Growing Season Green Surface Reflectance Trends, AK and Canada, 1984-2019 简介 该数据集提供了1984年至2019年期间ABoVE扩展研究域内472,890个湖泊的大地遥感卫星绿色表面反射率年度时间序列和衍生的年度生长季节&#xff08;6月和7月&#xff09;趋势。反射…...

DMA知识

提示&#xff1a;文章 文章目录 前言一、背景二、 2.1 2.2 总结 前言 前期疑问&#xff1a; 本文目标&#xff1a; 一、背景 2024年3月26日23:32:43 今天看了DMA存储器到存储器的DMA传输和存储器到外设的DMA实验&#xff0c;在keil仿真可以看到效果。还没有在protues和开发…...

Linux 系统 docker快速搭建PHP环境

PHP安装 ############################################################################# 1、直接拉取官方镜像 查找Docker Hub上的php镜像 docker search php 直接拉取官方镜像 docker run --name myphp --restartalways --network lnmp -d php:7.1-fpm 2、创建php容…...

逻辑设计问题 -- 设计一个函数

文章目录 设计一个函数函数接口规格说明运算符或者非运算符自由或成员运算符虚函数或非虚函数纯虚函数或者非纯虚函数静态或者非静态成员函数const 成员函数或者非const成员函数公共的、保护的或者私有的成员函数通过值、引用或者指针返回返回const 或者非const可选参数或者必要…...

RHCE 补充:判断服务状态

内容补充&#xff1a;判断服务状态 systemctl 命令 系统控制管理命令工具 常用指令 1、启动 systemctl start 程序名 若要启动多个程序名&#xff0c;使用空格隔开&#xff0c;下同 2、重启&#xff1a;类似主机先断电再启动的一个状态 systemctl restart 程序名 3、停…...

计算机网络:物理层 - 编码与调制

计算机网络&#xff1a;物理层 - 编码与调制 基本概念编码不归零制编码归零制编码曼彻斯特编码差分曼彻斯特编码 调制调幅调频调相混合调制 基本概念 在计算机网络中&#xff0c;计算机需要处理和传输用户的文字、图片、音频和视频&#xff0c;他们可以统称为消息数据&#xf…...

《量子计算:揭开未来科技新篇章》

随着科技的不断发展&#xff0c;量子计算作为一项颠覆性的技术逐渐走进人们的视野&#xff0c;引发了广泛的关注和探讨。本文将围绕量子计算的技术进展、技术原理、行业应用案例、未来趋势预测以及学习路线等方向&#xff0c;深入探讨这一领域的前沿动态和未来发展趋势。 量子…...

机器人机械手加装SycoTec 4060 ER-S电主轴高精密铣削加工

随着科技的不断发展&#xff0c;机器人技术正逐渐渗透到各个领域&#xff0c;展现出前所未有的潜力和应用价值。作为机器人技术的核心组成部分之一&#xff0c;机器人机械手以其高精度、高效率和高稳定性的优势&#xff0c;在机械加工、装配、检测等领域中发挥着举足轻重的作用…...

docker 共享内存不足问题

在启动容器时增加共享内存大小&#xff1a; 您可以通过在docker run命令中添加--shm-size参数来指定更大的共享内存大小。例如&#xff0c;如果您需要32GB的共享内存&#xff0c;可以这样做&#xff1a; docker run --shm-size32g -it your-docker-image 这里的your-docker-im…...

英语口语 3.27

keep It straight :竖着放 turn it to the side:横过来放 i get my shit done:shit(everything)任何事情 我都会去做的 that‘s what’s up 可以的可以的 thats cool zodiac sign :生肖 座 i sense that :我感受到了 talent”艺人 influencer&#xff1a;有影响力的人 …...

pytest之统一接口请求封装

pytest之统一接口请求封装 pytest的requests_util.pyrequests_util.py 接口自动化测试框架的封装yaml文件如何实现接口关联封装yaml文件如何实现动态参数的处理yaml文件如何实现文件上传有参数化时候&#xff0c;怎么实现断言yaml的数据量大怎么处理接口自动化框架的扩展&#…...

使用npm仓库的优先级以及.npmrc配置文件的使用

使用npm仓库的优先级以及.npmrc配置文件的使用 概念如何设置 registry&#xff08;包管理仓库&#xff09;1. 设置项目配置文件2. 设置用户配置文件3. 设置全局配置文件4. .npmrc文件可以配置的常见选项 概念 npm&#xff08;Node Package Manager&#xff09;是一个Node.js的…...

Netty源码剖析——ChannelHandlerContext 篇(三十七)

ChannelHandlerContext 作用及设计 ChannelHandlerContext 继承了出站方法调用接口和入站方法调用接口 ChannelOutboundInvoker 和 ChannelInboundInvoker 部分源码 这两个invoker就是针对入站或出站方法来的&#xff0c;就是在入站或出站 handler 的外层再包装一层&#xff0c…...

5.92 BCC工具之bitesize.py解读

一,工具简介 bitesize工具按进程名称显示请求块大小的I/O分布。 它通过监视磁盘上的读取和写入操作,记录每个操作的大小。再将跟踪到的 I/O 操作按照大小分组,通常是以 2 的幂次方(如 4K、8K、16K 等)进行划分,并统计每个大小范围内的 I/O 操作数量。 二,代码示例 #…...

jupyter notebook导出含中文的pdf(LaTex安装和Pandoc、MiKTex安装)

用jupyter notebook导出pdf时&#xff0c;因为报错信息&#xff0c;需要用到Tex nbconvert failed: xelatex not found on PATH, if you have not installed xelatex you may need to do so. Find further instructions at https://nbconvert.readthedocs.io/en/latest/install…...

压力测试(QPS)及测试工具Locust

压力测试&#xff1a; 通常指的是确定接口或服务能够处理的最大请求量&#xff08;吞吐量&#xff09;和并发用户数&#xff0c;同时保持合理的响应时间和稳定性。 性能目标 最大吞吐量&#xff1a;系统每秒可以处理的请求数。最大并发用户数&#xff1a;系统可以同时支持的…...

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…...

7.4.分块查找

一.分块查找的算法思想&#xff1a; 1.实例&#xff1a; 以上述图片的顺序表为例&#xff0c; 该顺序表的数据元素从整体来看是乱序的&#xff0c;但如果把这些数据元素分成一块一块的小区间&#xff0c; 第一个区间[0,1]索引上的数据元素都是小于等于10的&#xff0c; 第二…...

synchronized 学习

学习源&#xff1a; https://www.bilibili.com/video/BV1aJ411V763?spm_id_from333.788.videopod.episodes&vd_source32e1c41a9370911ab06d12fbc36c4ebc 1.应用场景 不超卖&#xff0c;也要考虑性能问题&#xff08;场景&#xff09; 2.常见面试问题&#xff1a; sync出…...

微信小程序之bind和catch

这两个呢&#xff0c;都是绑定事件用的&#xff0c;具体使用有些小区别。 官方文档&#xff1a; 事件冒泡处理不同 bind&#xff1a;绑定的事件会向上冒泡&#xff0c;即触发当前组件的事件后&#xff0c;还会继续触发父组件的相同事件。例如&#xff0c;有一个子视图绑定了b…...

python/java环境配置

环境变量放一起 python&#xff1a; 1.首先下载Python Python下载地址&#xff1a;Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个&#xff0c;然后自定义&#xff0c;全选 可以把前4个选上 3.环境配置 1&#xff09;搜高级系统设置 2…...

oracle与MySQL数据库之间数据同步的技术要点

Oracle与MySQL数据库之间的数据同步是一个涉及多个技术要点的复杂任务。由于Oracle和MySQL的架构差异&#xff0c;它们的数据同步要求既要保持数据的准确性和一致性&#xff0c;又要处理好性能问题。以下是一些主要的技术要点&#xff1a; 数据结构差异 数据类型差异&#xff…...

Java-41 深入浅出 Spring - 声明式事务的支持 事务配置 XML模式 XML+注解模式

点一下关注吧&#xff01;&#xff01;&#xff01;非常感谢&#xff01;&#xff01;持续更新&#xff01;&#xff01;&#xff01; &#x1f680; AI篇持续更新中&#xff01;&#xff08;长期更新&#xff09; 目前2025年06月05日更新到&#xff1a; AI炼丹日志-28 - Aud…...

Linux云原生安全:零信任架构与机密计算

Linux云原生安全&#xff1a;零信任架构与机密计算 构建坚不可摧的云原生防御体系 引言&#xff1a;云原生安全的范式革命 随着云原生技术的普及&#xff0c;安全边界正在从传统的网络边界向工作负载内部转移。Gartner预测&#xff0c;到2025年&#xff0c;零信任架构将成为超…...

【配置 YOLOX 用于按目录分类的图片数据集】

现在的图标点选越来越多&#xff0c;如何一步解决&#xff0c;采用 YOLOX 目标检测模式则可以轻松解决 要在 YOLOX 中使用按目录分类的图片数据集&#xff08;每个目录代表一个类别&#xff0c;目录下是该类别的所有图片&#xff09;&#xff0c;你需要进行以下配置步骤&#x…...

Axios请求超时重发机制

Axios 超时重新请求实现方案 在 Axios 中实现超时重新请求可以通过以下几种方式&#xff1a; 1. 使用拦截器实现自动重试 import axios from axios;// 创建axios实例 const instance axios.create();// 设置超时时间 instance.defaults.timeout 5000;// 最大重试次数 cons…...

在 Spring Boot 项目里,MYSQL中json类型字段使用

前言&#xff1a; 因为程序特殊需求导致&#xff0c;需要mysql数据库存储json类型数据&#xff0c;因此记录一下使用流程 1.java实体中新增字段 private List<User> users 2.增加mybatis-plus注解 TableField(typeHandler FastjsonTypeHandler.class) private Lis…...