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 的事件机制),观察者模式都能有效提升系统的可扩展性。

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

相关推荐
2601_962071573 小时前
【Java报错已解决】org.springframework.beans.factory.BeanCreationException
java·开发语言
zww89491113 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·eclipse
zww89491116 小时前
匿名树洞系统开发实战:从需求分析到部署指南
java·eclipse
黑马程序员毕设7 小时前
基于Java的医院药品管理系统的优化设计与实现
java·开发语言·spring boot·小程序·架构·课程设计·毕设
木井巳7 小时前
【BFS/DFS 解决 FloodFill 算法】太平洋大西洋水流问题
java·算法·leetcode·深度优先·广度优先·宽度优先·推荐算法
白山编程大哥8 小时前
Java 集合算法:从排序、查找到底层原理的实战指南
java·python·算法
devpotato8 小时前
缓存与数据库更新顺序不一致问题
java·数据库·redis
xcl09258 小时前
酒馆预约系统开发实战:从需求分析到上线全流程指南
java·spring boot·需求分析
Kyrie_kk8 小时前
Java--IO--Path文件访问
java·后端
qinqinzqq8 小时前
Maven POM 格式、Schema 与 XSD:一篇讲透
java·maven