观察者模式:事件处理机制与松耦合设计

server/2024/12/17 13:09:02/

目录

  • 1. 什么是观察者模式
  • 2. 为什么需要观察者模式
  • 3. 观察者模式的结构
  • 4. 实现示例
  • 5. Java内置的观察者实现
  • 6. 最佳实践与注意事项

1. 什么是观察者模式

观察者模式是一种行为型设计模式,它定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。当主题对象发生变化时,它的所有观察者都会收到通知并自动更新。

这种模式被广泛应用于事件处理系统中,比如:

  • GUI系统中的事件处理
  • 消息推送系统
  • 订阅发布机制

2. 为什么需要观察者模式

观察者模式主要解决以下问题:

  1. 解耦合:将观察者和被观察者解耦,使得它们可以独立变化
  2. 实现一对多关系:一个对象的状态改变可以通知多个订阅者
  3. 支持广播通信:不需要明确指定接收者,所有订阅者都能收到通知

3. 观察者模式的结构

UML类图

Subject
+attach(Observer observer)
+detach(Observer observer)
+notify()
ConcreteSubject
-state
+getState()
+setState()
Observer
+update()
ConcreteObserver
-state
+update()

核心角色

  1. Subject(主题)
    • 持有观察者集合
    • 提供注册和删除观察者的方法
    • 通知所有观察者的方法
  2. Observer(观察者)
    • 定义更新接口
    • 收到主题通知时进行更新
  3. ConcreteSubject(具体主题)
    • Subject 的具体实现类
    • 存储观察者感兴趣的状态
    • 当状态发生改变时通知观察者
  4. ConcreteObserver(具体观察者)
    • Observer 的具体实现类
    • 维护一个指向 ConcreteSubject 对象的引用
    • 存储感兴趣的状态,这些状态需要和主题的状态保持一致
    • 实现 Observer 的更新接口,使自身状态与主题的状态保持一致

4. 实现示例

让我们通过一个具体的例子来理解观察者模式。假设我们要实现一个天气监测系统:

java">// 观察者接口
public interface WeatherObserver {void update(float temperature, float humidity, float pressure);
}// 主题接口
public interface WeatherSubject {void registerObserver(WeatherObserver observer);void removeObserver(WeatherObserver observer);void notifyObservers();
}// 具体主题:气象站
public class WeatherStation implements WeatherSubject {private List<WeatherObserver> observers;private float temperature;private float humidity;private float pressure;public WeatherStation() {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 setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;notifyObservers();}
}// 具体观察者:显示当前天气
public class CurrentConditionsDisplay implements WeatherObserver {private float temperature;private float humidity;private float pressure;@Overridepublic void update(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;display();}public void display() {System.out.println("当前温度: " + temperature + "°C");System.out.println("当前湿度: " + humidity + "%");System.out.println("当前气压: " + pressure + "hPa");}
}// 使用示例
public class WeatherStationDemo {public static void main(String[] args) {WeatherStation weatherStation = new WeatherStation();CurrentConditionsDisplay display = new CurrentConditionsDisplay();// 注册观察者weatherStation.registerObserver(display);// 更新天气数据weatherStation.setMeasurements(25.2f, 65.0f, 1013.1f);}
}

运行结果:

当前温度: 25.2°C
当前湿度: 65.0%
当前气压: 1013.1hPa

运行结果说明:

  1. 首先创建了一个 WeatherStation 对象(主题)和一个 CurrentConditionsDisplay 对象(观察者)
  2. 通过 registerObserver() 方法将显示器注册为气象站的观察者
  3. 当调用 setMeasurements() 更新气象数据时:
    • 气象站内部的数据被更新
    • 自动调用 notifyObservers() 通知所有观察者
    • 观察者的 update() 方法被调用,接收最新数据
    • 显示器随即更新显示最新的气象信息

这个简单的例子展示了观察者模式的核心工作流程:对象状态改变 → 自动通知 → 观察者更新,整个过程中主题和观察者都保持松耦合。

5. Java内置的观察者实现

Java提供了内置的观察者模式支持,通过java.util.Observable类和java.util.Observer接口:

java">import java.util.Observable;
import java.util.Observer;// 继承Observable的气象站
public class JavaWeatherStation extends Observable {private float temperature;private float humidity;private float pressure;public void setMeasurements(float temperature, float humidity, float pressure) {this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;setChanged(); // 标记状态已改变notifyObservers(new float[]{temperature, humidity, pressure});}
}// 实现Observer接口的显示器
public class JavaCurrentConditionsDisplay implements Observer {@Overridepublic void update(Observable observable, Object arg) {if (arg instanceof float[]) {float[] measurements = (float[]) arg;float temperature = measurements[0];float humidity = measurements[1];float pressure = measurements[2];System.out.println("当前温度: " + temperature + "°C");System.out.println("当前湿度: " + humidity + "%");System.out.println("当前气压: " + pressure + "hPa");}}
}

注意:从Java 9开始,ObservableObserver已被标记为废弃,建议使用其他替代方案,如Flow API或自定义实现。

6. 最佳实践与注意事项

  1. 避免循环依赖
    • 确保观察者和主题之间不会形成循环依赖
    • 注意在通知观察者时不要触发新的更新循环
  2. 内存管理
    • 及时移除不再需要的观察者
    • 注意防止内存泄漏
  3. 线程安全
    • 在多线程环境下需要确保观察者列表的线程安全
    • 考虑使用线程安全的集合类
  4. 通知顺序
    • 不要依赖观察者的通知顺序
    • 观察者的处理逻辑应该相互独立
  5. 异常处理
    • 观察者的更新方法应该处理异常
    • 一个观察者的异常不应影响其他观察者

使用场景

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

  • 当一个对象的改变需要同时改变其他对象时
  • 当一个对象必须通知其他对象,而它又不知道这些对象是谁时
  • 当一个对象改变时,需要动态更新一组对象时

优点

  1. 符合开闭原则
  2. 可以在运行时建立对象之间的关系
  3. 支持广播通信

缺点

  1. 观察者模式可能导致广播风暴
  2. 如果观察者太多,通知的代价会很大
  3. 观察者之间的依赖关系不易跟踪

总结

观察者模式是一种强大的设计模式,它通过松耦合的方式实现了对象之间的一对多的依赖关系。通过合理使用观察者模式,我们可以构建出灵活、可维护的事件处理系统。在实际应用中,要根据具体场景选择合适的实现方式,并注意处理好各种边界情况。


http://www.ppmy.cn/server/150904.html

相关文章

YOLOv10改进,YOLOv10添加DLKA-Attention可变形大核注意力,WACV2024 ,二次C2f结构

摘要 作者引入了一种称为可变形大核注意力 (D-LKA Attention) 的新方法来增强医学图像分割。这种方法使用大型卷积内核有效地捕获体积上下文,避免了过多的计算需求。D-LKA Attention 还受益于可变形卷积,以适应不同的数据模式。 理论介绍 大核卷积(Large Kernel Convolu…

OpenCV相机标定与3D重建(19)将本质矩阵分解为旋转矩阵和平移向量函数decomposeEssentialMat()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 将本质矩阵分解为可能的旋转和平移。 cv::decomposeEssentialMat 是 OpenCV 库中的一个函数&#xff0c;用于将本质矩阵&#xff08;Essential M…

python paddle实现语音识别、语音合成

1. 安装vs c++编译环境 对于 Windows 系统,需要安装 Visual Studio 来完成 C++ 编译环境的安装。 Microsoft C++ Build Tools - Visual Studio 2. 安装conda conda create --prefix=D:\conda_envs\paddle_env python=3.9 conda activate D:\conda_envs\paddle_env 4. 安装…

【论文笔记】CLIP-guided Prototype Modulating for Few-shot Action Recognition

&#x1f34e;个人主页&#xff1a;小嗷犬的个人主页 &#x1f34a;个人网站&#xff1a;小嗷犬的技术小站 &#x1f96d;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;为万世开太平。 基本信息 标题: CLIP-guided Prototype Mo…

【JavaSE基础】第十七章:反射+设计模式

一、反射 1.反射(Reflection)&#xff1a;允许在程序运行状态中&#xff0c;可以获取任意类中的属性和方法&#xff0c;并且可以操作任意对象内部的属性和方法&#xff0c;这种动态获取类的信息及动态操作对象的属性和方法对应的机制称为反射机制。 2.类对象 和 类的对象(实例…

Python单例模式的优雅实现:元类与装饰器的结合

Python单例模式的优雅实现:元类与装饰器的结合 引言 单例模式是一种常用的设计模式,旨在确保一个类只有一个实例,并提供一个全局访问点。在多线程环境下,如何保证单例的线程安全是一个重要的问题。本文将深入探讨Python中使用元类和装饰器实现线程安全单例模式的两种方式…

Vue Web开发(五)

1. axios axios官方文档 异步库axios和mockjs模拟后端数据&#xff0c;axios是一个基于promise的HTTP库&#xff0c;使用npm i axios。在main.js中引入&#xff0c;需要绑定在Vue的prototype属性上&#xff0c;并重命名。   &#xff08;1&#xff09;main.js文件引用 imp…

使用Python实现手写数字识别

引言: 手写数字识别是“光学字符识别技术”(简称OCR)的一个分支,它研究的对象是:如何利用电子计算机自动辨认人手写在纸张上的阿拉伯数字。 在整个OCR领域中,最为困难的就是脱机手写字符的识别。到目前为止,尽管人们在脱机手写英文、汉字识别的研究中已取得很多可喜成就…