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

设计模式:观察者模式 - 实战

一、观察者模式场景

1.1 什么是观察者模式?
观察者模式(Observer Pattern)观察者模式是一种行为型设计模式,用于定义一种一对多的依赖关系,当对象的状态发生变化时,所有依赖于它的对象都会自动收到通知并更新。

核心思想观察者模式实现了对象之间的解耦:被观察者(Subject)专注于自身状态的管理,而观察者(Observer)专注于对状态变化的响应,二者通过通知机制进行交互

1.2 传统开发模式的三大死穴

强耦合陷阱:订单状态变更需要手动调用10+通知服务(邮件/SMS/物流…)

扩展噩梦:新增通知渠道必须修改核心业务代码(违反OCP原则)

性能瓶颈:同步调用链导致接口响应时间突破2秒红线

1.3 观察者模式的破局之道
事件驱动架构:业务逻辑与事件处理物理隔离

动态扩展能力:新增观察者零侵入核心系统

异步削峰:实测QPS提升300%(订单支付场景)

1.4 优点

解耦:被观察者和观察者之间的耦合度低,便于扩展。

动态联动:可以动态添加、移除观察者,灵活性强。

符合开闭原则:被观察者的状态变化通知机制对扩展开放,对修改关闭。

1.5 缺点

性能问题:观察者过多时,通知机制可能导致性能开销。

复杂性增加:过多的观察者与被观察者关系可能增加系统的复杂性。

可能产生循环依赖:若观察者与被观察者相互依赖,可能导致循环调用。

1.6 应用场景

事件驱动模型:如 UI 事件监听器(按钮点击等)。

发布-订阅机制:消息队列、事件总线等。

状态同步:某一对象的状态变化需要通知多个依赖对象时。

二、技术方案设计

2.1 架构演进对比
在这里插入图片描述

2.2 核心组件设计

[事件源] --发布--> [EventBus] --通知--> [观察者集群]↑                    ↖[事件对象]               [线程池分发]

三、Java原生实现

3.1 基于JDK的经典实现

// 支付成功事件定义
public class PaymentSuccessEvent extends EventObject {private final String orderId;private final BigDecimal amount;public PaymentSuccessEvent(Object source, String orderId, BigDecimal amount) {super(source);this.orderId = orderId;this.amount = amount;}
}// 支付服务(事件源)
public class PaymentService {private final List<EventListener> listeners = new CopyOnWriteArrayList<>();public void addListener(EventListener listener) {listeners.add(listener);}public void pay(String orderId, BigDecimal amount) {// 支付核心逻辑...notifyListeners(new PaymentSuccessEvent(this, orderId, amount));}private void notifyListeners(PaymentSuccessEvent event) {listeners.forEach(listener -> listener.onEvent(event));}
}// 邮件通知观察者
public class EmailNotifier implements EventListener {@Overridepublic void onEvent(EventObject event) {if (event instanceof PaymentSuccessEvent) {PaymentSuccessEvent e = (PaymentSuccessEvent) event;sendEmail(e.getOrderId(), e.getAmount());}}
}

3.2 Java9+改进方案

// 使用Flow API实现响应式流
public class PaymentPublisher implements Flow.Publisher<PaymentEvent> {private final Executor executor = ForkJoinPool.commonPool();private final List<Flow.Subscriber<? super PaymentEvent>> subscribers = new CopyOnWriteArrayList<>();@Overridepublic void subscribe(Flow.Subscriber<? super PaymentEvent> subscriber) {subscribers.add(subscriber);subscriber.onSubscribe(new PaymentSubscription(subscriber));}private class PaymentSubscription implements Flow.Subscription {private final Flow.Subscriber<? super PaymentEvent> subscriber;PaymentSubscription(Flow.Subscriber<? super PaymentEvent> subscriber) {this.subscriber = subscriber;}@Overridepublic void request(long n) {// 背压处理}@Overridepublic void cancel() {subscribers.remove(subscriber);}}
}

四、Spring生态进阶实现

4.1 基于ApplicationEvent

// 配置中心变更事件
public class ConfigUpdateEvent extends ApplicationEvent {private final String configKey;private final String newValue;public ConfigUpdateEvent(Object source, String configKey, String newValue) {super(source);this.configKey = configKey;this.newValue = newValue;}
}// 动态配置观察者
@Component
public class ConfigRefreshListener {@EventListener@Asyncpublic void handleConfigUpdate(ConfigUpdateEvent event) {refreshConfigCache(event.getConfigKey(), event.getNewValue());notifyAllServers(event);}
}// 事件发布
@Service
public class ConfigService {@Autowiredprivate ApplicationEventPublisher eventPublisher;public void updateConfig(String key, String value) {// 更新数据库eventPublisher.publishEvent(new ConfigUpdateEvent(this, key, value));}
}

4.2 注解驱动增强

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BusinessEventListener {String[] keys() default {};EventMode mode() default EventMode.ASYNC;
}// AOP切面处理
@Aspect
@Component
public class EventListenerAspect {@Around("@annotation(listener)")public Object processEvent(ProceedingJoinPoint pjp, BusinessEventListener listener) {EventObject event = (EventObject) pjp.getArgs()[0];if (shouldHandle(event, listener.keys())) {return switch (listener.mode()) {case ASYNC -> CompletableFuture.runAsync(() -> proceed(pjp));case TRANSACTIONAL -> executeInTransaction(pjp);default -> proceed(pjp);};}return null;}
}

五、生产级优化方案

5.1 性能优化策略
在这里插入图片描述

5.2 可靠性保障

// 事件持久化方案
public class PersistentEventBus {private final EventStoreRepository eventStore;@Transactional(propagation = Propagation.REQUIRES_NEW)public void publishWithPersistence(DomainEvent event) {eventStore.save(event);realPublish(event);}// 定时补偿任务@Scheduled(fixedRate = 60000)public void retryFailedEvents() {eventStore.findFailedEvents().forEach(event -> {try {realPublish(event);event.markAsSent();} catch (Exception e) {event.recordRetry();}});}
}

六、经典应用场景

6.1 电商订单系统

支付成功事件 → 库存扣减/物流触发/积分发放使用「发布-确认-补偿」机制保证最终一致性

6.2 微服务配置中心

配置变更事件 → 所有服务实例动态刷新结合Spring Cloud Bus实现集群通知

6.3 物联网数据采集

设备状态事件 → 实时监控/预警分析/大屏展示采用MQTT协议实现百万级设备连接

七、避坑指南

7.1 常见问题排查
内存泄漏:

检查观察者是否及时取消注册

使用WeakReference包装监听器

事件丢失:

增加本地事件持久化层

实现至少一次投递语义

循环触发:

在事件对象中添加traceId

设置最大传播深度阈值

7.2 生产注意事项
事件版本控制:使用Avro Schema管理事件格式

监控埋点:统计事件处理耗时/成功率

熔断降级:Hystrix隔离异常观察者

相关文章:

设计模式:观察者模式 - 实战

一、观察者模式场景 1.1 什么是观察者模式&#xff1f; 观察者模式&#xff08;Observer Pattern&#xff09;观察者模式是一种行为型设计模式&#xff0c;用于定义一种一对多的依赖关系&#xff0c;当对象的状态发生变化时&#xff0c;所有依赖于它的对象都会自动收到通知并更…...

8.8 Primary ODSA service without ODSA Portal

主要ODSA服务&#xff08;不使用ODSA门户&#xff09; 以下场景描述如下情况&#xff1a; • 主ODSA客户端应用程序被允许用于该类型的主设备&#xff0c;且对终端用户启用&#xff08;已授权&#xff09;。 • 服务提供商&#xff08;SP&#xff09;能够在不涉及ODSA门户Web服…...

YOLOv8 移动端升级:借助 GhostNetv2 主干网络,实现高效特征提取

文章目录 引言GhostNetv2概述GhostNet回顾GhostNetv2创新 YOLOv8主干网络改进原YOLOv8主干分析GhostNetv2主干替换方案整体架构设计关键模块实现 完整主干网络实现YOLOv8集成与训练模型集成训练技巧 性能对比与分析计算复杂度对比优势分析 部署优化建议结论与展望 引言 目标检…...

国产化Word处理控件Spire.Doc教程:在 C# 中打印 Word 文档终极指南

在 C# 中以编程方式打印 Word 文档可以简化业务工作流程、自动化报告和增强文档管理系统。本指南全面探讨如何使用Spire.Doc for .NET打印 Word 文档&#xff0c;涵盖从基本打印到高级自定义技术的所有内容。我们将逐步介绍每种情况下的实际代码示例&#xff0c;确保您能够在实…...

java的vscode扩展插件

在 Visual Studio Code (VSCode) 中&#xff0c;Java 开发可以通过多种方式得到支持&#xff0c;包括安装专门的扩展插件。下面是一些流行的 VSCode 扩展插件&#xff0c;可以帮助你更好地进行 Java 开发&#xff1a; Language Support for Java(TM) by Red Hat 官方支持&…...

谷歌:贝叶斯框架优化LLM推理反思

&#x1f4d6;标题&#xff1a;Beyond Markovian: Reflective Exploration via Bayes-Adaptive RL for LLM Reasoning &#x1f310;来源&#xff1a;arXiv, 2505.20561 &#x1f31f;摘要 通过强化学习 (RL) 训练的大型语言模型 (LLM) 表现出强大的推理能力和紧急反射行为&a…...

Qt SQL模块基础

Qt SQL模块基础 一、Qt SQL模块支持的数据库 官方帮助文档中的Qt支持的数据库驱动如下图&#xff1a; Qt SQL 模块中提供了一些常见的数据库驱动&#xff0c;包括网络型数据库&#xff0c;如Qracle、MS SQL Server、MySQL等&#xff0c;也包括简单的单机型数据库。 Qt SQL支…...

[9-3] 串口发送串口发送+接收 江协科技学习笔记(26个知识点)

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中断...

java 微服务中,微服务相互调用 feign 和flux 如何选择

在 Java 微服务中&#xff0c;Feign 和 Flux&#xff08;通过 WebClient 实现&#xff09;是两种不同的服务间调用方式&#xff0c;主要区别体现在编程模型、通信机制和适用场景上。 1. 编程模型 FeignFlux (WebClient)同步阻塞式&#xff1a;基于传统 Servlet 模型&#xff0…...

如何在Qt中绘制一个带有动画的弧形进度条?

如何在Qt中绘制一个弧形的进度条 在图形用户界面开发中&#xff0c;进度指示控件&#xff08;Progress Widget&#xff09;是非常常见且实用的组件。CCArcProgressWidget 是一个继承自 QWidget 的自定义控件&#xff0c;用于绘制圆弧形进度条。当然&#xff0c;笔者看了眼公开…...

参加技术会议,为程序人生的职业生涯成长添砖加瓦

参加技术会议,为程序人生的职业生涯成长添砖加瓦 关键词:技术会议、程序员职业生涯、职业成长、技术交流、人脉拓展、知识体系升级、职业竞争力 摘要:在快速迭代的IT技术领域,参加技术会议已成为程序员突破职业瓶颈、构建核心竞争力的重要途径。本文从技术会议的核心价值出…...

国产三维CAD皇冠CAD(CrownCAD)建模教程:汽车电池

在线解读『汽车电池』的三维建模流程&#xff0c;讲解3D草图、保存实体、拉伸凸台/基体、设置外观等操作技巧&#xff0c;一起和皇冠CAD&#xff08;CrownCAD&#xff09;学习制作步骤吧&#xff01; 汽车电池&#xff08;通常指铅酸蓄电池或锂离子电池&#xff09;是车辆电气系…...

记录算法笔记(2025.5.28)只出现一次的数字

给你一个 非空 整数数组 nums &#xff0c;除了某个元素只出现一次以外&#xff0c;其余每个元素均出现两次。找出那个只出现了一次的元素。 你必须设计并实现线性时间复杂度的算法来解决此问题&#xff0c;且该算法只使用常量额外空间。 示例 1 &#xff1a; 输入&#xff1…...

VMware-workstation安装教程--超详细(附带安装包)附带安装CentOS系统教程

VMware-workstation安装教程--超详细&#xff08;附带安装包&#xff09;附带安装CentOS系统教程 一、下载软件VMwware二、下载需要的镜像三、在VMware上安装系统 一、下载软件VMwware 二、下载需要的镜像 三、在VMware上安装系统 VMware 被 Broadcom&#xff08;博通&#x…...

2025年- H63-Lc171--33.搜索旋转排序数组(2次二分查找,需二刷)--Java版

1.题目描述 2.思路 输入&#xff1a;旋转后的数组 nums&#xff0c;和一个整数 target 输出&#xff1a;target 在 nums 中的下标&#xff0c;如果不存在&#xff0c;返回 -1 限制&#xff1a;时间复杂度为 O(log n)&#xff0c;所以不能用遍历&#xff0c;必须使用 二分查找…...

3D-激光SLAM笔记

目录 定位方案 编译tbb ros2humble安装 命令 colcon commond not found 栅格地图生成&#xff1a; evo画轨迹曲线 安装gtsam4.0.2 安装ceres-solver1.14.0 定位方案 1 方案一&#xff1a;改动最多 fasterlio 建图&#xff0c;加闭环优化&#xff0c;参考fast-lio增加关…...

Golang 配置国内代理

使用 GOPROXY 临时设置 export GOPROXYhttps://goproxy.cn,direct永久设置 go env -w GOPROXYhttps://goproxy.cn,direct再go get下载...

Android bindservice绑定服务,并同步返回service对象的两个方法

先上一段代码&#xff1a; private IDeviceService deviceService null; private ServiceConnection connnull; private synchronized void bindyourservice() { Intent intent new Intent();intent.setPackage("servicepackagename");intent.setAction("…...

5G 核心网 UE 状态深度剖析:机制、迁移与演进

摘要 本文围绕 5G 核心网中 UE(用户设备)状态展开系统分析,详细阐述了 UE 状态的定义、分类及特点,深入探讨各状态间的迁移流程与关键技术,并结合典型应用场景分析其实际价值。同时,对比 4G 技术剖析 5G 的改进之处,展望 6G 时代 UE 状态管理的演进方向,为 5G 网络优化…...

HomeKit 基本理解

概括 HomeKit 将用户的家庭自动化信息存储在数据库中&#xff0c;该数据库由苹果的内置iOS家庭应用程序、支持HomeKit的应用程序和其他开发人员的应用程序共享。所有这些应用程序都使用HomeKit框架作为对等程序访问数据库. Home 只是相当于 HomeKit 的表现层,其他应用在实现 …...

[SC]SystemC在CPU/GPU验证中的应用(三)

SystemC在CPU/GPU验证中的应用(三) 摘要:下面分享50个逐步升级SystemC编程能力的示例及建议的学习路线图。您可以一次一批地完成它们——从前五个基础的例子开始,然后转向channels, TLM, bus models, simple CPU/GPU kernels等等。在每个阶段掌握之后,再进行下一组…...

gunicorn多线程部署django导致的登陆错误

使用django写后端&#xff0c;认证系统使用了内存中的令牌存储&#xff08;authentication.py中的user_tokens字典&#xff09;。 from secrets import token_hex from .models import User# Create a custom token generation function def generate_token():return token_he…...

(LeetCode 每日一题) 909. 蛇梯棋 (广度优先搜索bfs)

题目&#xff1a;909. 蛇梯棋 思路&#xff1a;广度优先搜索bfs队列&#xff0c;时间复杂度0(6*n^2)。 细节看注释 C版本&#xff1a; class Solution { public:int snakesAndLadders(vector<vector<int>>& board) {int nboard.size();// vis[i]&#xff1a;…...

PostgreSQL ERROR: out of shared memory处理

使用pg_dump命令导出一个库的时候&#xff0c;报 pg_dump: error: query failed: ERROR: out of shared memory HINT: You might need to increase "max_locks_per_transaction". 从错误字面上看是超出内存大小了&#xff0c;建议增加max_locks_per_transaction参…...

生成https 证书步骤

一、OpenSSL下载 OpenSSL下载地址&#xff1a; https://slproweb.com/products/Win32OpenSSL.html 如果电脑是64位的就选择64位的 二、OpenSSL安装 双击打开.exe文件 开始安装&#xff0c;一直下一步&#xff0c;不过需要注意的是默认安装路径是C盘&#xff0c;可更改到其他盘…...

34、请求处理-【源码分析】-Model、Map原理

34、请求处理-【源码分析】-Model、Map原理 在 Spring Boot 中&#xff0c;处理请求时&#xff0c;控制器方法可以接收 Model 和 Map 类型的参数&#xff0c;用于向视图传递数据。以下是 Model 和 Map 参数处理的原理分析&#xff1a; ### 1. 参数解析过程 #### **1.1 确定参数…...

设计模式——适配器设计模式(结构型)

摘要 本文详细介绍了适配器设计模式&#xff0c;包括其定义、核心思想、角色、结构、实现方式、适用场景及实战示例。适配器模式是一种结构型设计模式&#xff0c;通过将一个类的接口转换成客户端期望的另一个接口&#xff0c;解决接口不兼容问题&#xff0c;提高系统灵活性和…...

小黑大语言模型通过设计demo进行应用探索:langchain中chain的简单理解demo

chain简介 LangChain 中的 Chain 模块‌在开发大型语言模型&#xff08;LLM&#xff09;驱动的应用程序中起着至关重要的作用。Chain是串联LLM能力与实际业务的关键桥梁&#xff0c;通过将多个工具和模块按逻辑串联起来&#xff0c;实现复杂任务的多步骤流程编排。 案例 通过…...

秒杀系统—5.第二版升级优化的技术文档三

大纲 8.秒杀系统的秒杀库存服务实现 9.秒杀系统的秒杀抢购服务实现 10.秒杀系统的秒杀下单服务实现 11.秒杀系统的页面渲染服务实现 12.秒杀系统的页面发布服务实现 8.秒杀系统的秒杀库存服务实现 (1)秒杀商品的库存在Redis中的结构 (2)库存分片并同步到Redis的实现 (3…...

[SC]SystemC在CPU/GPU验证中的应用(六)

SystemC在CPU/GPU验证中的应用(六) 摘要:下面分享50个逐步升级SystemC编程能力的示例及建议的学习路线图。您可以一次一批地完成它们——从前五个基础的例子开始,然后转向channels, TLM, bus models, simple CPU/GPU kernels等等。在每个阶段掌握之后,再进行下一组…...