Java设计模式之行为型模式(观察者模式)介绍与说明

一、模式结构

观察者模式包含以下四个角色:

  1. Subject(主题/被观察者)
    • 维护观察者列表,提供注册(registerObserver)、移除(removeObserver)观察者的方法,并定义通知所有观察者的方法(notifyObservers)。
    • 示例:天气数据(WeatherData)、优衣库品牌决策(UniqloBrandDecision)。
  2. Observer(观察者)
    • 定义更新接口(update),用于接收主题的通知并执行响应逻辑。
    • 示例:天气显示组件(CurrentConditionsDisplay)、消费者(Consumer)。
  3. ConcreteSubject(具体主题)
    • 实现主题接口,管理观察者列表,并在状态变化时触发通知。例如,WeatherData类在温度、湿度等数据更新时调用notifyObservers
  4. ConcreteObserver(具体观察者)
    • 实现观察者接口,定义具体响应逻辑。例如,CurrentConditionsDisplay在接收到数据后更新显示内容。

二、核心实现步骤

  1. 定义观察者接口:声明update方法,参数可为数据对象或主题引用(推模型或拉模型)。
  2. 实现具体观察者:在update方法中处理主题状态变化,例如更新UI或执行业务逻辑。
  3. 定义主题接口:包含观察者管理方法和通知方法。
  4. 实现具体主题:维护观察者列表,在状态变化时遍历并调用update方法。

三、代码示例(气象站系统)

java 复制代码
// 观察者接口
public interface Observer {
    void update(float temp, float humidity, float pressure);
}
// 主题接口
public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
}
// 具体主题类(天气数据)
public class WeatherData implements Subject {
    private List observers = new ArrayList<>();
    private float temperature, humidity, pressure;
    @Override
    public void registerObserver(Observer o) { observers.add(o); }
    @Override
    public void removeObserver(Observer o) { observers.remove(o); }
    @Override
    public void notifyObservers() {
        for (Observer o : observers) {
            o.update(temperature, humidity, pressure);
        }
    }
    public void measurementsChanged() {
        notifyObservers();
    }
    public void setMeasurements(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}
// 具体观察者类(当前天气显示)
public class CurrentConditionsDisplay implements Observer {
    private float temp, humidity;
    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temp = temp;
        this.humidity = humidity;
        display();
    }
    private void display() {
        System.out.println("当前温度:" + temp + "℃,湿度:" + humidity + "%");
    }
}

四、适用场景

  1. 事件驱动系统:如GUI事件处理、按钮点击监听。
  2. 实时数据监控:股票价格变动、传感器数据更新。
  3. 订阅/发布模型:邮件订阅、RSS订阅、消息队列。
  4. 跨模块通知:订单状态变更通知多个服务。

五、优缺点分析

优点 缺点
- 解耦主题与观察者,符合开闭原则。 - 观察者过多时性能下降。
- 动态扩展观察者,无需修改核心逻辑。 - 通知顺序不可控,可能引发依赖链问题。
- 支持广播通信,实现事件驱动机制。 - 循环依赖可能导致栈溢出。

六、高级应用与优化

  1. 异步通知:使用线程池处理观察者回调,避免阻塞主题线程。
  2. 事件参数化:通过事件对象(如VoteEvent)传递具体数据,增强灵活性。
  3. 弱引用机制:防止内存泄漏(如使用WeakReference存储观察者)。
  4. 分布式扩展:结合消息队列(如Kafka)实现跨进程观察者。

七、Java内置支持(已过时)

JDK提供java.util.ObservableObserver类,但因设计缺陷(如需手动调用setChanged())已被标记为过时。推荐自定义实现或使用现代框架(如Spring的ApplicationEvent)。


总结

观察者模式通过解耦主题与观察者,实现了灵活的通知机制,广泛应用于事件驱动、实时监控等场景。开发者需权衡性能与扩展性,合理设计通知模型(推/拉)和生命周期管理。

相关推荐
Anastasiozzzz4 分钟前
Java Lambda 揭秘:从匿名内部类到底层原理的深度解析
java·开发语言
骇客野人6 分钟前
通过脚本推送Docker镜像
java·docker·容器
Hello_Embed9 分钟前
libmodbus 移植 STM32(USB 串口后端篇)
笔记·stm32·单片机·嵌入式·freertos·libmodbus
张祥64228890419 分钟前
RTKLIB源码和理论结合分析笔记三
笔记
铁蛋AI编程实战23 分钟前
通义千问 3.5 Turbo GGUF 量化版本地部署教程:4G 显存即可运行,数据永不泄露
java·人工智能·python
日更嵌入式的打工仔27 分钟前
0欧电阻作用
笔记
晚霞的不甘34 分钟前
CANN 编译器深度解析:UB、L1 与 Global Memory 的协同调度机制
java·后端·spring·架构·音视频
SunnyDays101136 分钟前
使用 Java 冻结 Excel 行和列:完整指南
java·冻结excel行和列
奶茶精Gaaa1 小时前
工具分享--json在线转换工具
学习
摇滚侠1 小时前
在 SpringBoot 项目中,开发工具使用 IDEA,.idea 目录下的文件需要提交吗
java·spring boot·intellij-idea