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

设计模式:观察者模式 (Observer) 案例详解

目录

一、引言:为什么需要观察者模式?

二、观察者模式的核心原理

1. 角色划分

2. 类图关系

三、经典案例解析

案例1:天气监测系统

案例2:股票价格监控系统

案例3:MVC架构中的模型-视图分离

案例4:Java内置事件监听机制

四、进阶技巧与注意事项

1. 避免循环依赖

2. 异步通知

3. Java内置支持

五、对比其他设计模式

六、总结与建议


一、引言:为什么需要观察者模式?

在软件开发中,对象之间的耦合度越高,代码的维护性和扩展性越差。例如:

  • 事件处理:当一个对象的状态变化需要通知多个其他对象时(如GUI按钮点击触发多个事件)。
  • 数据同步:当数据源更新时,多个依赖该数据的对象需要自动刷新(如股票价格变动通知投资者)。
    传统方案中,对象间直接调用会导致强耦合,而观察者模式通过解耦解决了这一问题。

二、观察者模式的核心原理

1. 角色划分
  • Subject(主题):维护观察者列表,提供注册、移除和通知观察者的接口。
  • Observer(观察者):定义更新接口,接收主题的通知并自动更新。
  • ConcreteSubject(具体主题):实现主题接口,管理观察者列表,状态变化时通知观察者。
  • ConcreteObserver(具体观察者):实现观察者接口,定义收到通知后的具体行为。
2. 类图关系
[Subject] <-- [ConcreteSubject]▼List<Observer>▲
[Observer] --> [ConcreteObserver]

三、经典案例解析

案例1:天气监测系统

背景:气象站实时采集温度、湿度数据,多个显示设备(如当前状况、统计图表)需同步更新。

实现步骤

  1. 定义主题接口
    interface Subject {void registerObserver(Observer o);void removeObserver(Observer o);void notifyObservers();
    }
    
  2. 实现具体主题
    class WeatherData implements Subject {private List<Observer> observers;private float temperature;public void setMeasurements(float temp, float hum) {this.temperature = temp;notifyObservers();}public void notifyObservers() {for (Observer observer : observers) {observer.update(temperature);}}// 注册、移除观察者方法省略
    }
    
  3. 定义观察者接口
    interface Observer {void update(float temperature);
    }
    
  4. 实现具体观察者
    class CurrentConditionsDisplay implements Observer {public void update(float temperature) {System.out.println("当前温度:" + temperature + "°C");}
    }
    

效果

  • 新增显示设备(如统计图表)只需实现Observer接口,无需修改WeatherData
  • 主题与观察者解耦,支持动态扩展。
案例2:股票价格监控系统

背景:投资者订阅股票信息,当价格变动时需实时通知所有订阅者。

实现亮点

  • 主题Stock类维护价格和观察者列表。
  • 观察者Investor类实现更新逻辑,如触发买入/卖出操作。
  • 动态订阅:投资者可随时添加或取消订阅。

代码片段

class Stock implements Subject {private List<Observer> investors = new ArrayList<>();private double price;public void setPrice(double newPrice) {this.price = newPrice;notifyObservers();}public void notifyObservers() {for (Observer investor : investors) {investor.update(price);}}
}
案例3:MVC架构中的模型-视图分离

背景:模型层(Model)数据变化时,多个视图层(如柱状图、饼图)需自动更新。

实现逻辑

  • 模型:作为主题,存储数据并通知视图。
  • 视图:作为观察者,订阅模型更新。
  • 优势:视图与模型解耦,支持任意数量的视图扩展。

示例

class Model implements Subject {private int data;public void setData(int newData) {this.data = newData;notifyObservers();}
}
class BarChart implements Observer {public void update(int data) {System.out.println("柱状图更新:" + data);}
}
案例4:Java内置事件监听机制

背景:GUI按钮点击事件需触发多个操作(如弹窗、日志记录)。

实现原理

  • 事件源:按钮作为主题,触发事件。
  • 事件监听器:观察者实现ActionListener接口,处理事件。

代码示例

JButton button = new JButton("Click");
button.addActionListener(e -> System.out.println("按钮被点击!"));

四、进阶技巧与注意事项

1. 避免循环依赖

若观察者在update()中修改主题状态,可能导致无限递归。解决方案:

  • 限制通知层级(如仅通知一次)。
  • 使用标志位判断是否正在通知。
2. 异步通知

在复杂系统中,同步通知可能阻塞主线程。可通过异步回调消息队列优化:

new Thread(() -> notifyObservers()).start();
3. Java内置支持

JDK提供java.util.Observablejava.util.Observer,但存在以下问题:

  • 观察者与主题强绑定,难以扩展。
  • 建议自定义接口,提升灵活性。

五、对比其他设计模式

模式核心目标观察者模式适用场景
策略模式算法替换需动态切换行为(如排序算法)
中介者模式多对象通信协调复杂对象网状关系(如聊天室)
发布-订阅事件分发(如消息队列)高并发、异步事件处理

六、总结与建议

观察者模式通过解耦广播机制,完美解决对象间一对多依赖问题。在实际开发中:

  1. 优先解耦:将主题与观察者职责分离,避免直接调用。
  2. 灵活扩展:通过接口定义,支持动态添加新观察者。
  3. 谨慎处理循环依赖:设计时需考虑通知顺序和条件。

实践建议

  • 初学者从简单案例(如天气系统)入手,理解核心逻辑。
  • 在职开发者可研究开源框架(如RxJava、Spring事件机制)中的实现。

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

相关文章:

  • 消息队列:Redis Stream到RabbitMQ的转换
  • MongoDB06 - MongoDB 地理空间
  • PyQt5—QPushButton 功能 API 学习笔记
  • Zynq7020 Linux更新启动分区文件导致文件大小为0的处理方式
  • 力扣第84题-柱状图中最大的矩形
  • Webpack中的Loader详解
  • 用户行为序列建模(篇六)-【阿里】DSIN
  • 实战篇----利用 LangChain 和 BERT 用于命名实体识别-----完整代码
  • flask使用-链接mongoDB
  • Python爬虫-爬取汽车之家全部汽车品牌及车型数据
  • ListExtension 扩展方法增加 转DataTable()方法
  • Lua现学现卖
  • DOP数据开放平台(真实线上项目)
  • 电商返利APP架构设计:如何基于Spring Cloud构建高并发佣金结算系统
  • OpenLayers 下载地图切片
  • 解决cursor无法下载插件等网络问题
  • vue-29(创建 Nuxt.js 项目)
  • 从用户到权限:解密 AWS IAM Identity Center 的授权之道
  • 给定一个没有重复元素的数组,写出生成这个数组的MaxTree的函数
  • TDengine 如何使用 MQTT 采集数据?
  • lambda、function基础/响应式编程基础
  • [论文阅读] 软件工程 | 微前端在电商领域的实践:一项案例研究的深度解析
  • NLP中的同义词替换及我踩的坑
  • 创客匠人视角:创始人 IP 打造为何成为知识变现的核心竞争力
  • 【算法深练】单调栈:有序入栈,及时删除垃圾数据
  • 鸿蒙5:组件监听和部分状态管理V2
  • 为何需要防爆平板?它究竟有何能耐?
  • 【龙泽科技】新能源汽车故障诊断仿真教学软件【吉利几何G6】
  • 学习使用dotnet-dump工具分析.net内存转储文件(2)
  • vue-28(服务器端渲染(SSR)简介及其优势)