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

发布订阅者模式

前言

在Java中,发布和订阅者模式(Publish-Subscribe Pattern)是一种行为设计模式,它允许对象(称为发布者)发送消息(称为事件)给多个感兴趣的接收者(称为订阅者),而不需要知道这些接收者的具体细节。这种模式解耦了发布者和订阅者之间的直接联系,使得它们可以独立地变化和发展;

发布订阅者模式优点

解耦:发布者和订阅者之间不直接通信,它们通过中介(如事件总线)进行交互。这种解耦使得发布者和订阅者可以独立地改变和扩展,而不会影响到对方。例如,在软件开发中,如果你更改了发布事件的逻辑,但只要不改变事件的名称和格式,那么订阅这些事件的代码就不需要修改;


灵活性:一个发布者可以有多个订阅者,同时一个订阅者也可以订阅多个发布者发布的事件。这种灵活性使得系统能够轻松地处理复杂的交互场景;


扩展性:由于发布者和订阅者之间的解耦,向系统中添加新的订阅者或发布者变得非常简单。你不需要修改现有的代码,只需要将新的订阅者注册到中介上,或将新的发布者连接到中介上即可;

模拟实现

        电视总台(发布者)

        喜剧节目观众(订阅者)

        恐怖节目观众(订阅者)

实现“电视总台”发布影片清单(清单包含了多种影片类型如喜剧、恐怖类),使用发布订阅者模式系统自动将对应影片分类发送给订阅了相应类型(喜剧/恐怖)的观众;如订阅了喜剧栏目的观众将收到喜剧栏目的影片推送。订阅了恐怖栏目的用户将收到恐怖栏目的影片推送;

代码片段

1.常量类

/*** 常量类*/
public class Constant {// 喜剧节目public static final Integer COMEDY_CHANNEL = 1;// 恐怖节目public static final Integer TERROR_CHANNEL = 2;
}

2.事件类

import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.context.ApplicationEvent;
import java.util.List;
/*** 定义事件(继承ApplicationEvent类)*      节目事件*/
@Data
@Builder
public class ProgramEvent extends ApplicationEvent {// 节目清单private List<Program> programList;// 构造方法public ProgramEvent(Object source) {super(source);}// 构造方法public ProgramEvent(List<Program> programList) {super("");this.programList = programList;}/*** 节目实体 - 内部类*/@Data@AllArgsConstructor@NoArgsConstructorpublic static class Program{private String id; // 节目idprivate String programName; // 节目名称private Integer channel; // 节目分类(1: 喜剧 2:恐怖)}
}

3.喜剧/恐怖订阅者

import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.util.List;
import static fw.client.utils.designmode.listener.Constant.COMEDY_CHANNEL;
/*** 定义监听器(订阅者)(实现ApplicationListener方法)*      喜剧节目观众订阅者(当电视台发布喜剧节目时 喜剧节目观众订阅者会获取到发布的喜剧节目);*/
@Component
public class ComedyAudienceListener implements ApplicationListener<ProgramEvent> {/*** 当ProgramEvent发布就会执行 onApplicationEvent 方法;*/@Overridepublic void onApplicationEvent(ProgramEvent event) {// 获取电视台推送的所有节目清单List<ProgramEvent.Program> programList = event.getProgramList();programList.stream().filter(program -> COMEDY_CHANNEL == program.getChannel()).forEach(program -> System.out.println("喜剧节目观众接收到电视台推送的喜剧节目:" + program.getProgramName()));}
}
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
import java.util.List;
import static fw.client.utils.designmode.listener.Constant.TERROR_CHANNEL;
/*** 定义监听器(订阅者)(实现ApplicationListener方法)*      恐怖节目观众订阅者(当电视台发布恐怖节目时 恐怖节目订阅者会获取到发布的恐怖节目);*/
@Component
public class TerrorAudienceListener implements ApplicationListener<ProgramEvent> {/*** 当ProgramEvent发布就会执行 onApplicationEvent 方法;*/@Overridepublic void onApplicationEvent(ProgramEvent event) {// 获取电视台推送的所有节目清单List<ProgramEvent.Program> programList = event.getProgramList();programList.stream().filter(program -> TERROR_CHANNEL == program.getChannel()).forEach(program -> System.out.println("恐怖节目观众接收到电视台推送的恐怖节目:" + program.getProgramName()));}
}

4.事件广播器

import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Component;
/***  定义事件广播器*      通过调用publish方法传入事件。对应订阅(监听)事件器会获取到传入publish数据;*/
@Component
public class EventPublishUtil implements ApplicationEventPublisherAware {private static ApplicationEventPublisher applicationEventPublisher;@Overridepublic void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {EventPublishUtil.applicationEventPublisher = applicationEventPublisher;}/*** 广播事件*/public static void publish(ApplicationEvent event){applicationEventPublisher.publishEvent(event);}
}

5.发布者

        使用SpringBoot的测试方法模式发布者;

import fw.client.utils.designmode.listener.EventPublishUtil;
import fw.client.utils.designmode.listener.ProgramEvent;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.ArrayList;
import java.util.List;
/*** 发布订阅者模式*/
@SpringBootTest
public class ListenerMdoeTest {/*** TV - 发布者*/@Testpublic void TVPublisher() {// 构造喜剧节目ProgramEvent.Program comedyProgram1 = new ProgramEvent.Program("A1","唐伯虎点秋香",1);ProgramEvent.Program comedyProgram2 = new ProgramEvent.Program("A2","大话西游",1);// 构造恐怖节目ProgramEvent.Program terrorProgram1 = new ProgramEvent.Program("B1","山村老尸",2);// 构造节目清单List<ProgramEvent.Program> programsList = new ArrayList<>();programsList.add(comedyProgram1);programsList.add(comedyProgram2);programsList.add(terrorProgram1);// 发布电视节目清单EventPublishUtil.publish(new ProgramEvent(programsList));}
}

测试结果

# 控制台输出

喜剧节目观众接收到电视台推送的喜剧节目:唐伯虎点秋香
喜剧节目观众接收到电视台推送的喜剧节目:大话西游
恐怖节目观众接收到电视台推送的恐怖节目:山村老尸

 补充说明

        发布订阅者模式扩展性很好,假如此时新增加一个影片类型如(冒险类)。我们只需要增加一个新的订阅者去处理这部分数据即可。对于“发布者”方代码来说无需做任何处理;

http://www.xdnf.cn/news/10068.html

相关文章:

  • stm32无刷电机控制_滑膜观测器更改电机如何调整?
  • 《java创世手记》---java基础篇(下)
  • 招工招聘系统开发——适配多元场景,满足企业多样化招聘需求
  • 91.评论日记
  • 2025年文学与文化发展国际会议(ICLCD 2025)
  • FEMFAT许可分析的数据可视化方法
  • 重读《人件》Peopleware -(13)Ⅱ 办公环境 Ⅵ 电话
  • 如何通过一次需求评审,让项目效率提升50%?
  • 【定昌linux开发板】设置密码的有效时间
  • 【Python】第二弹:搭建 Python 环境
  • 创建一个网站、有了云服务器还需要什么?
  • [创业之路-394]:企业战略管理-战略制定/设计-从业绩差距到机会差距的跨越,从存量市场到增量市场的转型之道
  • 晨控CK-FR03与TwinCAT3配置EtherCAT通讯连接手册
  • 开发者体验提升:打造高效愉悦的开发环境
  • Prometheus + Grafana + Cadvisor:构建高效企业级服务监控体系
  • 如何选择适合的冲压件清洗机?冲压件清洗机的选购指南
  • TypeScript 中感叹号(!)两种位置用法
  • Baklib内容中台AI赋能智能服务升级
  • 从 leanback 的npe崩溃谈起
  • 深度解析:跨学科论文 +“概念迁移表” 模板写作全流程
  • 安装RHEL9.x操作系统
  • 56、Ocelot 概述
  • RSTP协议:秒级收敛解析
  • 建站新手:我与SiteServerCMS的爱恨情仇(一)
  • #Js篇:BlobFile对象URL.createObjectURL()fetchlocationnavigatornew URl
  • 打卡day41
  • 2505软考高项第一、二批真题终极汇总
  • 【MySQL】事务及隔离性
  • 气镇阀是什么?
  • excel导出引发的cpu问题