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

观察者模式

观察者模式:解耦依赖的事件响应机制

一、观察者模式的核心定义

观察者模式(Observer Pattern) 是一种行为型设计模式,定义了对象之间的一对多依赖关系:当一个对象(被观察者 / 主题)的状态发生变化时,所有依赖它的对象(观察者)都会自动收到通知并进行更新。这种模式的核心是解耦被观察者与观察者,让两者无需知晓对方的具体实现,仅通过统一的接口交互。

简单来说,观察者模式就像 “订阅 - 通知” 机制:比如公众号(被观察者)发布新文章时,所有关注该公众号的用户(观察者)都会收到推送,用户无需主动刷新,公众号也无需单独联系每个用户。

二、核心角色与结构

观察者模式包含四个核心角色,各角色职责明确,通过接口实现解耦:

  1. 抽象主题(Subject):定义被观察者的核心行为,包括注册观察者、移除观察者、通知所有观察者的接口。

  2. 具体主题(Concrete Subject):抽象主题的实现类,维护观察者列表,当自身状态变化时,调用通知方法触发所有观察者更新。

  3. 抽象观察者(Observer):定义观察者的更新接口,包含一个接收通知并处理的方法(如 update())。

  4. 具体观察者(Concrete Observer):抽象观察者的实现类,实现更新接口,根据被观察者的通知执行具体业务逻辑。

结构示意图(简化):

[具体主题] ← 注册/移除 → [抽象观察者]↑                          ↓通知                      实现↓                          ↑[具体观察者1]、[具体观察者2]、...

三、代码实现示例(Java)

以 “气象站发布天气数据,多个显示终端接收更新” 为例,实现观察者模式:

1. 抽象主题(Subject)

public interface WeatherSubject {// 注册观察者void registerObserver(WeatherObserver observer);// 移除观察者void removeObserver(WeatherObserver observer);// 通知所有观察者void notifyObservers();}

2. 具体主题(Concrete Subject)

import java.util.ArrayList;import java.util.List;public class WeatherData implements WeatherSubject {// 维护观察者列表private List observers;// 被观察的状态(温度、湿度、气压)private float temperature;private float humidity;private float pressure;public WeatherData() {observers = new ArrayList<>();}// 注册观察者@Overridepublic void registerObserver(WeatherObserver observer) {observers.add(observer);}// 移除观察者@Overridepublic void removeObserver(WeatherObserver observer) {observers.remove(observer);}// 通知所有观察者(状态变化时调用)@Overridepublic void notifyObservers() {for (WeatherObserver observer : observers) {// 传递最新状态,触发观察者更新observer.update(temperature, humidity, pressure);}}// 模拟气象站更新数据(实际场景中可能是传感器采集)public void setWeatherData(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;// 数据更新后,自动通知观察者notifyObservers();}}

3. 抽象观察者(Observer)

public interface WeatherObserver {// 接收通知并更新(参数为被观察者的最新状态)void update(float temperature, float humidity, float pressure);}

4. 具体观察者(Concrete Observer)

// 手机APP显示终端public class PhoneDisplay implements WeatherObserver {@Overridepublic void update(float temperature, float humidity, float pressure) {System.out.println("手机APP收到天气更新:");System.out.printf("温度:%.1f℃,湿度:%.1f%%,气压:%.1f hPa%n",temperature, humidity, pressure);}}// 电视天气预报终端public class TVDisplay implements WeatherObserver {@Overridepublic void update(float temperature, float humidity, float pressure) {System.out.println("n电视天气预报更新:");System.out.printf("今日气温:%.1f℃,空气湿度:%.1f%%,气压稳定在%.1f hPa%n",temperature, humidity, pressure);}}

5. 测试代码

public class ObserverTest {public static void main(String[] args) {// 创建被观察者(气象站)WeatherData weatherData = new WeatherData();// 创建观察者(显示终端)WeatherObserver phoneDisplay = new PhoneDisplay();WeatherObserver tvDisplay = new TVDisplay();// 注册观察者weatherData.registerObserver(phoneDisplay);weatherData.registerObserver(tvDisplay);// 模拟气象站更新数据System.out.println("=== 第一次更新天气数据 ===");weatherData.setWeatherData(25.5f, 60.2f, 1013.2f);System.out.println("n=== 第二次更新天气数据 ===");weatherData.setWeatherData(27.8f, 55.0f, 1012.5f);// 移除手机APP观察者weatherData.removeObserver(phoneDisplay);System.out.println("n=== 第三次更新天气数据(已移除手机APP) ===");weatherData.setWeatherData(23.1f, 70.5f, 1014.0f);}}

输出结果

=== 第一次更新天气数据 ===手机APP收到天气更新:温度:25.5℃,湿度:60.2%,气压:1013.2 hPa电视天气预报更新:今日气温:25.5℃,空气湿度:60.2%,气压稳定在1013.2 hPa=== 第二次更新天气数据 ===手机APP收到天气更新:温度:27.8℃,湿度:55.0%,气压:1012.5 hPa电视天气预报更新:今日气温:27.8℃,空气湿度:55.0%,气压稳定在1012.5 hPa=== 第三次更新天气数据(已移除手机APP) ===电视天气预报更新:今日气温:23.1℃,空气湿度:70.5%,气压稳定在1014.0 hPa

四、适用场景

观察者模式适用于以下场景:

  1. 对象间存在一对多依赖:一个对象状态变化需要联动多个对象响应(如:电商订单支付成功后,通知库存扣减、物流创建、积分增加)。

  2. 需要解耦依赖关系:避免被观察者与观察者直接耦合(如:消息队列的生产者 - 消费者模型,生产者无需知道消费者是谁)。

  3. 动态添加 / 移除观察者:需要灵活增减响应对象(如:网站的订阅功能,用户可随时关注 / 取消关注)。

五、优缺点分析

优点

  1. 解耦性强:被观察者与观察者通过接口交互,互不依赖具体实现,符合 “开闭原则”(新增观察者无需修改被观察者代码)。

  2. 响应及时:被观察者状态变化时,观察者自动收到通知,无需主动查询(“推模式” 高效)。

  3. 扩展性好:可随时添加新的观察者,或修改观察者的处理逻辑,不影响整体架构。

缺点

  1. 通知开销大:若观察者数量过多,被观察者通知所有观察者的过程会消耗较多资源,可能导致响应延迟。

  2. 循环依赖风险:若观察者与被观察者相互依赖,可能引发循环通知,导致系统崩溃。

  3. 顺序不可控:默认情况下,观察者的更新顺序由被观察者的通知顺序决定,若需指定顺序需额外处理。

六、扩展与变体

  1. 推模式 vs 拉模式
  • 推模式(本文示例):被观察者主动将状态数据推送给观察者,观察者被动接收。

  • 拉模式:被观察者仅通知 “状态已变”,观察者主动从被观察者获取所需数据(适合观察者需要不同状态的场景)。

  1. Java 内置支持:JDK 提供 java.util.Observable(抽象主题)和 java.util.Observer(抽象观察者),但因设计缺陷(如 Observable 是类而非接口,灵活性不足),实际开发中更推荐自定义接口实现。

  2. 结合其他模式:常与单例模式(确保被观察者唯一)、工厂模式(创建观察者实例)结合使用。

http://www.zskr.cn/news/83690.html

相关文章:

  • 详细介绍:Chrome HSTS(HTTP Strict Transport Security)
  • 2025年12月上海别墅装修,上海极简风装修,上海新中式装修公司权威推荐,设计实力与市场口碑深度解析 - 品牌鉴赏师
  • 2025年机械手数控车床品牌价格排行:前十名多少钱一台?英伟达液冷数控车/车铣复合数控机床/医疗器械数控机床数控车床采购排行榜 - 品牌推荐师
  • 聚焦2025:这些数控车床品牌是军工精密加工的保障,液冷接头数控机床/军工配件数控机床/空调配件数控机床/动力刀塔数控车数控车床批发排行 - 品牌推荐师
  • 【笔记】队列
  • 【笔记】队列
  • ZROJ 3272. 地皮
  • Conda 常用命令总结01
  • 英语_错题集_时态
  • 鸿蒙PC平台三方库移植实战:以libogg库移植为例(附完整移植流程与工具链配置) - 教程
  • 详细介绍:时间复杂度和空间复杂度
  • 小清新数论练手题01
  • 详细介绍:制造行业:销采一体化CRM如何破解行业痛点?
  • AI元人文构想:为价值安家,让优化有度
  • 10401_基于Springboot的植物园售票管理系统
  • 12.11 程序员修炼之道:从小工到专家 第八章 注重实效的项目 - GENGAR
  • task5
  • Flink学习笔记:多流 Join
  • 1-Year XTOOL D9 EV Update Service: Keep Diagnostics Current for Euro/American Vehicles
  • AI智能相机未来应用 - 指南
  • Boost Diagnostics with Autel MaxiVCI V150 Wireless Dongle – CAN FD/DOIP for 900 Series Scanners
  • 1-Year XTOOL X100 PADS Update: Keep Your Tool Updated for Euro/American Vehicles
  • 面向对象编程
  • 实用指南:《嵌入式成长系列之51单片机 --- Keil5创建工程》
  • python —— 求解斐波那契数列
  • 机器学习超参数调优:十个实用的贝叶斯优化(Bayesian Optimization)进阶技巧
  • 模糊测试助力黑客攻防:关键信息泄露漏洞挖掘实录
  • 访答:数字化时代的知识管理新范式
  • uni-app微信小应用相机组件二次拍照白屏问题的排查与解除
  • 【Ubuntu】一些用于学习/问题解决的文章