Java 设计模式:观察者模式详解

Java 设计模式:观察者模式详解

观察者模式(Observer Pattern)是一种行为型设计模式,它定义了对象之间的一对多依赖关系,当一个对象的状态发生变化时,所有依赖它的对象都会收到通知并自动更新。这种模式广泛用于事件监听和发布-订阅场景。本文将介绍观察者模式的定义、实现方式及其在 Java 中的应用。

1. 什么是观察者模式?

观察者模式的核心思想是:通过建立一个主题(Subject)和多个观察者(Observer)之间的订阅关系,实现状态变化的动态通知。它解耦了主体和观察者,使得系统更灵活、可扩展。

模式结构

  • 抽象主题(Subject):维护观察者列表,提供添加、删除和通知观察者的方法。
  • 具体主题(Concrete Subject):实现主题接口,状态变化时通知观察者。
  • 抽象观察者(Observer):定义更新接口,接收通知后执行操作。
  • 具体观察者(Concrete Observer):实现更新方法,响应状态变化。

2. 观察者模式的实现方式

以下是一个简单的示例:模拟一个天气站,天气数据更新时通知多个显示设备。

2.1 定义抽象观察者接口

java 复制代码
public interface Observer {
    void update(float temperature, float humidity); // 更新方法
}

2.2 定义抽象主题接口

java 复制代码
public interface Subject {
    void registerObserver(Observer observer); // 注册观察者
    void removeObserver(Observer observer);   // 移除观察者
    void notifyObservers();                   // 通知所有观察者
}

2.3 实现具体主题

java 复制代码
import java.util.ArrayList;
import java.util.List;

public class WeatherStation implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;

    public WeatherStation() {
        this.observers = new ArrayList<>();
    }

    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update(temperature, humidity);
        }
    }

    // 更新天气数据并通知观察者
    public void setMeasurements(float temperature, float humidity) {
        this.temperature = temperature;
        this.humidity = humidity;
        notifyObservers();
    }
}

2.4 实现具体观察者

java 复制代码
public class DisplayDevice implements Observer {
    private String deviceName;

    public DisplayDevice(String deviceName) {
        this.deviceName = deviceName;
    }

    @Override
    public void update(float temperature, float humidity) {
        System.out.println(deviceName + " 收到更新: 温度 = " + temperature + "°C, 湿度 = " + humidity + "%");
    }
}

2.5 客户端使用

java 复制代码
public class Client {
    public static void main(String[] args) {
        // 创建主题
        WeatherStation weatherStation = new WeatherStation();

        // 创建观察者
        DisplayDevice display1 = new DisplayDevice("显示屏1");
        DisplayDevice display2 = new DisplayDevice("显示屏2");

        // 注册观察者
        weatherStation.registerObserver(display1);
        weatherStation.registerObserver(display2);

        // 更新天气数据
        weatherStation.setMeasurements(25.5f, 60.0f);

        // 移除一个观察者
        weatherStation.removeObserver(display1);

        // 再次更新
        weatherStation.setMeasurements(28.0f, 55.0f);
    }
}

输出结果

复制代码
显示屏1 收到更新: 温度 = 25.5°C, 湿度 = 60.0%
显示屏2 收到更新: 温度 = 25.5°C, 湿度 = 60.0%
显示屏2 收到更新: 温度 = 28.0°C, 湿度 = 55.0%

3. Java 中的内置支持

Java 提供了 java.util.Observable 类和 java.util.Observer 接口,可以直接实现观察者模式。不过,这些类在 Java 9 中已被标记为过时,推荐使用自定义实现或事件监听机制。

示例:使用 Observable

java 复制代码
import java.util.Observable;
import java.util.Observer;

class WeatherData extends Observable {
    private float temperature;

    public void setTemperature(float temperature) {
        this.temperature = temperature;
        setChanged(); // 标记状态变化
        notifyObservers(temperature);
    }
}

class Display implements Observer {
    @Override
    public void update(Observable o, Object arg) {
        System.out.println("温度更新为: " + arg + "°C");
    }
}

public class Client {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        Display display = new Display();
        weatherData.addObserver(display);
        weatherData.setTemperature(26.0f);
    }
}

4. 观察者模式的优缺点

优点

  1. 解耦主体与观察者:主题和观察者之间松耦合,可独立变化。
  2. 支持广播通信:一个状态变化可通知多个观察者。
  3. 动态扩展:运行时可增删观察者,灵活性高。

缺点

  1. 通知开销:观察者过多时,通知过程可能影响性能。
  2. 内存泄漏风险:未及时移除观察者可能导致引用残留。
  3. 复杂性增加:大规模系统中管理观察者关系可能变得复杂。

5. 实际应用场景

  • GUI 事件监听:如 Swing 或 JavaFX 中的按钮点击事件。
  • 发布-订阅系统:如消息队列(Kafka、RabbitMQ)的简化版。
  • 状态监控:如天气预报、股票价格更新。

示例:Java 中的 ActionListener

java 复制代码
button.addActionListener(e -> System.out.println("按钮被点击"));

这里,ActionListener 是观察者,按钮是主题。


6. 与发布-订阅模式的区别

  • 观察者模式:主题直接通知观察者,耦合度稍高。
  • 发布-订阅模式:通过中间件(如事件总线)解耦,发布者和订阅者无直接联系。

7. 总结

观察者模式是一种强大的行为模式,适用于需要动态响应的场景。通过主题和观察者的解耦设计,它提供了灵活的状态通知机制。在 Java 中,无论是自定义实现还是借助框架(如 Spring 的事件机制),观察者模式都能有效提升系统的可扩展性。

希望这篇博文能帮助你掌握观察者模式的精髓!如果有其他设计模式相关问题,欢迎留言讨论。

相关推荐
阿杆5 分钟前
🤯我写了一套无敌的参数校验组件④ | 现已支持 i18n
java·spring
小样vvv6 分钟前
【微服务管理】注册中心:分布式系统的基石
java·数据库·微服务
amagi6009 分钟前
Java中的正则表达式(Regular Expression)
java
喵手16 分钟前
如何快速掌握 Java 反射之获取类的字段?
java·后端·java ee
AronTing19 分钟前
06- 服务网格实战:从 Istio 核心原理到微服务治理升级
java·后端·架构
奋进的小暄19 分钟前
贪心算法(18)(java)距离相等的条形码
java·开发语言·贪心算法
雷渊20 分钟前
Elasticsearch查询为什么这么快
java
雷渊23 分钟前
RocketMQ和kafka一样有重平衡的问题吗?
java·后端·面试
码农周29 分钟前
Spring Boot 启动后自动执行 Service 方法终极指南
java·spring boot·后端
Hanson8532 分钟前
系统性能优化总结与思考-第一部分
java·开发语言