深度剖析观察者模式:从理论到实战的Java实现

在软件设计中,观察者模式(Observer Pattern) 是一种高频使用的行为型设计模式,它定义了对象之间一对多的依赖关系,使得当一个对象状态改变时,其所有依赖对象(观察者)会自动收到通知并更新。这种模式在事件驱动系统、GUI框架、实时数据处理等领域应用广泛。本文将从模式原理、Java实现、应用场景、源码级优化等角度,深度剖析观察者模式的设计哲学与实践技巧。

一、观察者模式的核心思想

观察者模式的核心是解耦被观察者(Subject)与观察者(Observer),其设计目标包括:

  1. 动态订阅与取消订阅:观察者可以灵活注册或解除对主题的关注。

  2. 状态同步:主题状态变化时,所有观察者能自动响应。

  3. 松耦合:主题无需知道观察者的具体实现细节,仅依赖抽象接口。

模式角色划分
  • Subject(主题):维护观察者列表,提供注册、注销和通知方法。

  • ConcreteSubject(具体主题):实现Subject,存储状态,并在状态变化时触发通知。

  • Observer(观察者):定义更新接口,供主题调用。

  • ConcreteObserver(具体观察者):实现Observer接口,执行具体业务逻辑。


二、Java实现观察者模式:原生支持与自定义实现

1. Java内置观察者模式(java.util.Observable)

Java早期通过 Observable 类和 Observer 接口提供了观察者模式的原生支持,但因其设计缺陷(如Observable是类而非接口),在Java 9后被标记为废弃。以下是经典实现:

// 被观察者(继承Observable)
public class WeatherStation extends Observable {private float temperature;public void setTemperature(float temperature) {this.temperature = temperature;setChanged();    // 标记状态变化notifyObservers(temperature); // 通知观察者(可传递数据)}
}// 观察者(实现Observer接口)
public class Display implements Observer {@Overridepublic void update(Observable o, Object arg) {if (o instanceof WeatherStation) {System.out.println("温度更新: " + arg + "°C");}}
}// 使用示例
public class Client {public static void main(String[] args) {WeatherStation station = new WeatherStation();Display display = new Display();station.addObserver(display);station.setTemperature(25.5f); // 触发通知}
}
2. 自定义观察者模式实现(推荐)

为避免Java内置实现的局限性,可自定义观察者模式:

// 主题接口
public interface Subject<T> {void registerObserver(Observer<T> observer);void removeObserver(Observer<T> observer);void notifyObservers(T data);
}// 具体主题
public class WeatherStation implements Subject<Float> {private List<Observer<Float>> observers = new ArrayList<>();private float temperature;@Overridepublic void registerObserver(Observer<Float> observer) {observers.add(observer);}@Overridepublic void notifyObservers(Float data) {observers.forEach(observer -> observer.update(data));}public void setTemperature(float temperature) {this.temperature = temperature;notifyObservers(temperature);}
}// 观察者接口(泛型支持)
public interface Observer<T> {void update(T data);
}// 具体观察者
public class Display implements Observer<Float> {@Overridepublic void update(Float temperature) {System.out.println("[Display] 当前温度: " + temperature);}
}

优势分析

  • 类型安全:通过泛型避免强制类型转换。

  • 灵活性:Subject和Observer接口可自由扩展。

  • 解耦彻底:不依赖Java废弃类。


三、观察者模式的进阶应用与优化

1. 异步通知机制

在高并发场景中,同步通知可能阻塞主题线程。可通过线程池实现异步通知:

// 在Subject实现类中注入线程池
private ExecutorService executor = Executors.newCachedThreadPool();public void notifyObservers(T data) {observers.forEach(observer -> executor.submit(() -> observer.update(data)));
}
2. 防止观察者阻塞

若某个观察者处理时间过长,可能影响整体性能。可引入超时机制熔断策略

3. 观察者链与责任传递

观察者可形成责任链,在链中传递事件,直至被处理(类似事件冒泡)。


四、观察者模式的典型应用场景

1. GUI事件监听

例如Java Swing中的ActionListener,Android的OnClickListener

2. 分布式系统消息队列

如Kafka的生产者-消费者模型,本质是观察者模式的扩展。

3. Spring框架的事件机制

Spring的ApplicationEventApplicationListener实现了观察者模式,支持应用内事件驱动编程。

// 自定义事件
public class OrderEvent extends ApplicationEvent {public OrderEvent(Object source, String message) {super(source);this.message = message;}
}// 监听器
@Component
public class OrderListener implements ApplicationListener<OrderEvent> {@Overridepublic void onApplicationEvent(OrderEvent event) {System.out.println("收到订单事件: " + event.getMessage());}
}// 发布事件
applicationContext.publishEvent(new OrderEvent(this, "订单创建成功"));

五、观察者模式的优缺点与替代方案

优点
  • 符合开闭原则:新增观察者无需修改主题代码。

  • 动态建立对象间关系。

缺点
  • 通知顺序不可控:观察者接收通知的顺序不确定。

  • 循环依赖风险:观察者与主题相互引用可能导致内存泄漏。

替代方案
  • 发布-订阅模式:通过中间代理(如消息队列)彻底解耦生产者和消费者。

  • 响应式编程:如RxJava、Project Reactor,提供更强大的流处理能力。


六、总结

观察者模式是事件驱动架构的基石,其核心在于构建灵活、松耦合的交互系统。在Java生态中,无论是传统GUI开发,还是现代Spring框架、响应式编程,观察者模式的身影无处不在。开发者需根据场景选择合适实现方式,并注意线程安全、性能优化等关键问题。理解观察者模式,是掌握高扩展性系统设计的重要一步

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

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

相关文章

ComfyUI流程图生图原理详解

一、引言 ComfyUI 是一款功能强大的工具&#xff0c;在图像生成等领域有着广泛应用。本文补充一点ComfyUI 的安装与配置过程遇到的问题&#xff0c;并深入剖析图生图过程及相关参数&#xff0c;帮助读者快速入门并深入理解其原理。 二、ComfyUI 的安装与配置中遇到的问题 &a…

无人机遥感图像拼接及处理实践技术:生态环境监测、农业、林业等领域,结合图像拼接与处理技术,能够帮助我们更高效地进行地表空间要素的动态监测与分析

近年来&#xff0c;无人机技术在遥感领域的应用越来越广泛&#xff0c;尤其是在生态环境监测、农业、林业等领域&#xff0c;无人机遥感图像的处理与分析成为了科研和业务化工作中的重要环节。通过无人机获取的高分辨率影像数据&#xff0c;结合图像拼接与处理技术&#xff0c;…

web渗透测试之反弹shell SSRF结合redis结合伪协议 redis 未授权访问漏洞

目录 未授权访问漏洞利用:redis 反弹shell 漏洞原因就是&#xff1a; 反弹shell利用方式 反弹shell指的是什么 : 反弹shell的前提条件 步骤: redis未授权访问的三种利用手段反弹shell 利用定时任务反弹shell 攻击主机下设置 写入 webshell 步骤 利用公钥认证写入ro…

【Vue】打包vue3+vite项目发布到github page的完整过程

文章目录 第一步&#xff1a;打包第二步&#xff1a;github仓库设置第三步&#xff1a;安装插件gh-pages第四步&#xff1a;两个配置第五步&#xff1a;上传github其他问题1. 路由2.待补充 参考文章&#xff1a; 环境&#xff1a; vue3vite windows11&#xff08;使用终端即可&…

Win32/C++ 字符串操作实用工具

CStrUtils.h #pragma once#include <string> #include <vector> #include <windows.h> #include <tchar.h>#ifdef _UNICODE using _tstring std::wstring; #else using _tstring std::string; #endif// 字符串转换实用工具 namespace CStrUtils {//…

【C++前缀和】1074. 元素和为目标值的子矩阵数量|2189

本文涉及的基础知识点 C算法&#xff1a;前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 LeetCode1074. 元素和为目标值的子矩阵数量 给出矩阵 matrix 和目标值 target&#xff0c;返回元素总和等于目标值的非空子矩阵的数量。 子矩阵 x1, y1, x2, y2 是满…

【安当产品应用案例100集】037-强化OpenVPN安全防线的卓越之选——安当ASP身份认证系统

在当前数字化时代&#xff0c;网络安全已成为企业发展的重要组成部分。对于使用OpenVPN的企业而言&#xff0c;确保远程访问的安全性尤为重要。安当ASP身份认证系统凭借其强大的功能和便捷的集成方式&#xff0c;为OpenVPN的二次登录认证提供了理想的解决方案&#xff0c;特别是…

基于进化式大语言模型的下一代漏洞挖掘范式:智能对抗与自适应攻防体系

摘要 本文提出了一种基于进化式大语言模型(Evolutionary LLM)的智能漏洞挖掘框架,突破了传统静态分析的局限,构建了具备对抗性思维的动态攻防体系。通过引入深度强化学习与多模态感知机制,实现了漏洞挖掘过程的自适应进化,在RCE、SQLi、XXE等关键漏洞类型的检测中达到97…

2025年数据资产管理解决方案:资料合集,从基础知识到行业应用的全面解析

在数字化时代&#xff0c;数据已成为企业最宝贵的资产之一。如何有效地管理和利用这些数据&#xff0c;将其转化为实际的经济价值&#xff0c;已成为企业面临的重要课题。 本文将通过数据资产解决方案、数据资产行业报告白皮书、数据资产政策汇编、数据资产基础知识以及数据资…

【linux学习指南】模拟线程封装与智能指针shared_ptr

文章目录 &#x1f4dd;线程封装&#x1f309; Thread.hpp&#x1f309; Makefile &#x1f320;线程封装第一版&#x1f309; Makefile:&#x1f309;Main.cc&#x1f309; Thread.hpp: &#x1f320;线程封装第二版&#x1f309; Thread.hpp:&#x1f309; Main.cc &#x1f…

k8s的安装

1. k8s的安装 192.168.48.6 master01 192.168.481.6 node01 192.168.48.26 node02 三台机器一起操作 1.swapoff -a &#xff1a;关闭交换分区 2. iptables -F && iptables -t nat -F && iptables -t mangle -F && iptables -X 3. cat > /etc/sy…

字节跳动大模型应用 Go 开发框架 —— Eino 实践

前言 开发基于大模型的软件应用&#xff0c;就像指挥一支足球队&#xff1a;组件是能力各异的队员&#xff0c;编排是灵活多变的战术&#xff0c;数据是流转的足球。Eino 是字节跳动开源的大模型应用开发框架&#xff0c;拥有稳定的内核&#xff0c;灵活的扩展性&#xff0c;完…

redis之数据库

文章目录 服务器中的数据库切换数据库数据库键空间读写键空间时的维护操作 设置键的生存时间或过期时间保存过期时间过期键的判定过期键删除策略清性删除策略的实现定期删除策略的实现 总结 服务器中的数据库 Redis服务器将所有数据库都保存在服务器状态redis.h/redisServer结…

Qt文本高亮显示【QSyntaxHighlighter】功能代码讲解

QSyntaxHighlighter 是 Qt 框架中的一个重要类&#xff0c;专门用于为文本内容提供语法高亮功能。它广泛应用于文本编辑器、代码编辑器、日志查看器等应用程序中&#xff0c;允许开发者对文本中的不同部分应用不同的格式&#xff0c;如字体颜色、背景色、加粗等。通过这个类&am…

MS08067练武场--WP

免责声明&#xff1a;本文仅用于学习和研究目的&#xff0c;不鼓励或支持任何非法活动。所有技术内容仅供个人技术提升使用&#xff0c;未经授权不得用于攻击、侵犯或破坏他人系统。我们不对因使用本文内容而引起的任何法律责任或损失承担责任。 注&#xff1a;此文章为快速通关…

WPF正则表达式验证输入是否包含中文字母数字,不能是纯符号

1、验证纯中文 string pattern "[\u4e00-\u9fa5]"; // 创建Regex对象 Regex regex new Regex(pattern); // 判断输入字符串是否包含中文 if (!regex.IsMatch(name)) { //resultTextBlock.Text …

【Matlab优化算法-第13期】基于多目标优化算法的水库流量调度

一、前言 水库流量优化是水资源管理中的一个重要环节&#xff0c;通过合理调度水库流量&#xff0c;可以有效平衡防洪、发电和水资源利用等多方面的需求。本文将介绍一个水库流量优化模型&#xff0c;包括其约束条件、目标函数以及应用场景。 二、模型概述 水库流量优化模型…

《qt open3d中添加随机点采样》

qt open3d中添加随机点采样 效果展示二、流程三、代码效果展示 二、流程 创建动作,链接到槽函数,并把动作放置菜单栏 参照前文 三、代码 1、槽函数实现 void on_actionFilterRandomDownSample_triggered();void MainWindow::on_act

【图片转换PDF】多个文件夹里图片逐个批量转换成多个pdf软件,子文件夹单独合并转换,子文件夹单独批量转换,基于Py的解决方案

建筑设计公司在项目执行过程中&#xff0c;会产生大量的设计图纸、效果图、实景照片等图片资料。这些资料按照项目名称、阶段、专业等维度存放在多个文件夹和子文件夹中。 操作需求&#xff1a;为了方便内部管理和向客户交付完整的设计方案&#xff0c;公司需要将每个项目文件…

Windows 安装 DeepSeek 教程和open webui 图形化部署(非docker)

Windows 安装 Ollama : 步骤 1&#xff1a;下载并安装 Ollama 官网&#xff1a;奥拉马 点击下载 选择windows版本。 双击安装包 点击【Install】&#xff08;注意&#xff1a;安装包是直接安装在C盘的&#xff0c;并不支持更改路径&#xff0c;因此C盘的空间必须要至少大于5…