java23种设计模式-观察者模式

ops/2025/2/27 22:29:19/

观察者模式(Observer Pattern)学习笔记


编程相关书籍分享:https://blog.csdn.net/weixin_47763579/article/details/145855793
DeepSeek使用技巧pdf资料分享:https://blog.csdn.net/weixin_47763579/article/details/145884039


1. 模式定义

行为型设计模式,定义对象间的一种一对多依赖关系,当一个对象状态发生改变时,所有依赖它的对象都会得到通知并自动更新。又称为发布-订阅模式。

2. 适用场景

✅ 需要实现事件触发机制
✅ 存在多个对象依赖一个对象状态的场景
✅ 需要实现广播通信机制
✅ 需要解耦观察者与被观察者
✅ 需要动态增减观察者对象

3. 模式结构

notifies
«interface»
Subject
+registerObserver()
+removeObserver()
+notifyObservers()
«interface»
Observer
+update()
ConcreteSubject
-state
-observers: List
+getState()
+setState()
ConcreteObserverA
+update()
ConcreteObserverB
+update()

4. 核心角色

角色说明
Subject抽象主题(被观察者),定义注册、删除、通知观察者的接口
ConcreteSubject具体主题,维护观察者列表,状态改变时通知所有观察者
Observer抽象观察者,定义更新接口
ConcreteObserver具体观察者,实现更新逻辑

5. 代码示例

5.1 气象站监控示例

// 抽象主题
interface WeatherSubject {void registerObserver(WeatherObserver o);void removeObserver(WeatherObserver o);void notifyObservers();
}// 具体主题
class WeatherStation implements WeatherSubject {private List<WeatherObserver> observers = new ArrayList<>();private float temperature;private float humidity;public void setMeasurements(float temp, float humidity) {this.temperature = temp;this.humidity = humidity;notifyObservers();}public void registerObserver(WeatherObserver o) {observers.add(o);}public void removeObserver(WeatherObserver o) {observers.remove(o);}public void notifyObservers() {for (WeatherObserver o : observers) {o.update(temperature, humidity);}}
}// 抽象观察者
interface WeatherObserver {void update(float temp, float humidity);
}// 具体观察者
class CurrentConditionsDisplay implements WeatherObserver {public void update(float temp, float humidity) {System.out.printf("当前天气状况:温度%.1f℃ 湿度%.1f%%\n", temp, humidity);}
}class StatisticsDisplay implements WeatherObserver {public void update(float temp, float humidity) {// 实现统计逻辑System.out.println("更新统计数据显示...");}
}// 客户端
public class Client {public static void main(String[] args) {WeatherStation station = new WeatherStation();WeatherObserver currentDisplay = new CurrentConditionsDisplay();WeatherObserver statisticsDisplay = new StatisticsDisplay();station.registerObserver(currentDisplay);station.registerObserver(statisticsDisplay);station.setMeasurements(25.5f, 65.0f);/* 输出:当前天气状况:温度25.5℃ 湿度65.0%更新统计数据显示... */}
}

6. 模式变种

6.1 推拉模型对比

模型类型数据传递方式特点
主题主动发送完整数据给观察者观察者被动接收,可能收到不需要的数据
观察者主动从主题获取所需数据需要时获取,减少不必要数据传输
// 拉模型实现示例
interface PullObserver {void update(WeatherSubject subject);
}class PullWeatherDisplay implements PullObserver {public void update(WeatherSubject subject) {if (subject instanceof WeatherStation) {WeatherStation ws = (WeatherStation)subject;System.out.println("温度:" + ws.getTemperature());}}
}

7. 优缺点分析

✔️ 优点

  • 实现松耦合
  • 支持动态添加/删除观察者
  • 符合开闭原则
  • 支持广播通信

缺点

  • 通知顺序不可控
  • 观察者过多时影响性能
  • 循环依赖可能导致系统崩溃
  • 观察者可能收到不相关通知

8. 相关模式对比

模式目的关键区别
发布-订阅模式消息通知机制通过消息代理解耦,支持更复杂路由
中介者模式对象间交互集中控制通信,观察者模式是分布式通知
责任链模式请求传递观察者模式是单向通知机制

9. 实际应用案例

  • Java Swing的事件监听机制(ActionListener
  • Spring框架的ApplicationEventApplicationListener
  • Android的BroadcastReceiver
  • JavaBeans的PropertyChangeListener
  • Reactor编程模型
  • Vue.js的响应式系统
  • Kafka消息队列

10. 最佳实践建议

  1. 使用Java内置实现
// Java 9之前可用(已过时)
import java.util.Observable;
import java.util.Observer;// Java 9+推荐使用PropertyChangeSupport
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
  1. 防止内存泄漏
// 及时移除观察者
subject.addObserver(observer);
// ...
subject.deleteObserver(observer);
  1. 异步通知优化
// 使用线程池异步通知
ExecutorService executor = Executors.newCachedThreadPool();
public void notifyObservers() {for (Observer o : observers) {executor.submit(() -> o.update(data));}
}
  1. 使用弱引用(WeakReference):
// 防止观察者无法被垃圾回收
List<WeakReference<Observer>> weakObservers = new ArrayList<>();public void registerObserver(Observer o) {weakObservers.add(new WeakReference<>(o));
}
  1. 事件过滤机制
// 添加事件类型过滤
interface EventObserver {void update(EventType type, Object data);
}enum EventType { TEMP_CHANGE, HUMIDITY_CHANGE }

11. 扩展应用(Spring事件机制)

// 自定义事件
public class OrderCreatedEvent extends ApplicationEvent {private Order order;public OrderCreatedEvent(Object source, Order order) {super(source);this.order = order;}// getter...
}// 事件发布者
@Service
class OrderService {@Autowiredprivate ApplicationEventPublisher publisher;public void createOrder(Order order) {// 创建订单逻辑...publisher.publishEvent(new OrderCreatedEvent(this, order));}
}// 事件监听者
@Component
class NotificationService {@EventListenerpublic void handleOrderCreated(OrderCreatedEvent event) {// 发送通知逻辑...}
}

🔍 设计原则体现

  1. 开闭原则(OCP):新增观察者无需修改主题
  2. 松耦合原则:主题与观察者互相不知道对方细节
  3. 单一职责原则:主题管理状态,观察者处理通知

通过观察者模式,可以实现高效的事件通知机制,特别适合需要实现实时数据同步、事件驱动架构的场景。该模式在GUI开发、分布式系统和框架设计中应用广泛,是解耦组件关系的经典解决方案。


http://www.ppmy.cn/ops/161782.html

相关文章

日本IT|SQL工程师的工作内容以及所需的技能·资格

SQLエンジニアとは&#xff1f; 1.データベースの設計・開発、管理、運用を担うエンジニア データ抽出と整形 SQLエンジニアにおいて、データの抽出と整形は重要な仕事です。 リレーショナルデータベースではテーブルという形式でデータを管理しており、複数のテーブルから…

应对现代生活的健康养生指南

在科技飞速发展的现代社会&#xff0c;人们的生活方式发生了巨大改变&#xff0c;随之而来的是一系列健康问题。快节奏的生活、高强度的工作以及电子产品的过度使用&#xff0c;让我们的身体承受着前所未有的压力。因此&#xff0c;掌握正确的健康养生方法迫在眉睫。 针对久坐不…

编程小白冲Kaggle每日打卡(13)--kaggle学堂:<机器学习简介>基础数据探索

Kaggle官方课程链接&#xff1a;Basic Data Exploration 本专栏旨在Kaggle官方课程的汉化&#xff0c;让大家更方便地看懂。 Basic Data Exploration 加载并理解您的数据。 使用Pandas熟悉您的数据 任何机器学习项目的第一步都是熟悉数据。您将使用Pandas库进行此操作。Pand…

将夸克网盘的webdav挂载成本地磁盘驱动器时报错“405“

1 准备 alist挂载夸克网盘完毕。网页浏览器处可以访问夸克网盘里的文件。 2 故障现象 但是用RaiDrive或rclone等将之挂载成本地磁盘会报错"405"。 3 解法 alist的web管理页面上给“用户&#xff08;一般是admin&#xff09;->编辑->权限"里的webdav读…

Spring 创建对象的流程

1. 故事背景 想象一下&#xff0c;你是一个老板&#xff0c;要开一家公司。公司里有很多员工&#xff08;对象&#xff09;&#xff0c;每个员工都有自己的职责和依赖关系&#xff08;比如&#xff0c;程序员需要电脑&#xff0c;销售需要电话等&#xff09;。传统方式是你自己…

PyEcharts 数据可视化:从入门到实战

一、PyEcharts 简介 PyEcharts 是基于百度开源可视化库 ECharts 的 Python 数据可视化工具&#xff0c;支持生成交互式的 HTML 格式图表。相较于 Matplotlib 等静态图表库&#xff0c;PyEcharts 具有以下优势&#xff1a; 丰富的图表类型&#xff08;30&#xff09;动态交互功…

毕业项目推荐:基于yolov8/yolo11的苹果叶片病害检测识别系统(python+卷积神经网络)

文章目录 概要一、整体资源介绍技术要点功能展示&#xff1a;功能1 支持单张图片识别功能2 支持遍历文件夹识别功能3 支持识别视频文件功能4 支持摄像头识别功能5 支持结果文件导出&#xff08;xls格式&#xff09;功能6 支持切换检测到的目标查看 二、数据集三、算法介绍1. YO…

洛谷 P8705:[蓝桥杯 2020 省 B1] 填空题之“试题 E :矩阵” ← 卡特兰数

【题目来源】 https://www.luogu.com.cn/problem/P8705 【题目描述】 把 1∼2020 放在 21010 的矩阵里。要求同一行中右边的比左边大&#xff0c;同一列中下边的比上边的大。一共有多少种方案? 答案很大&#xff0c;你只需要给出方案数除以 2020 的余数即可。 【答案提交】 …