云计算百科
云计算领域专业知识百科平台

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

一、观察者模式简介

观察者模式(Observer Pattern)是一种行为型设计模式它定义了对象之间的一对多依赖关系。当一个对象(主题)的状态发生改变时,所有依赖于它的对象(观察者)都会自动收到通知并更新。这种模式又称为发布-订阅模式,广泛应用于事件监听、消息推送、实时数据更新等场景。

1. 核心思想

观察者模式的核心是解耦。主题(Subject)不需要知道观察者(Observer)的具体实现,只需通过接口进行交互。观察者可以动态注册或取消订阅主题的状态变化,从而实现灵活的扩展性和维护性。


二、观察者模式的结构

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

  • Subject(主题/被观察者) 定义注册、删除和通知观察者的接口,维护观察者列表。

  • ConcreteSubject(具体主题) 实现Subject接口,管理自身状态,并在状态变化时通知所有观察者。

  • Observer(观察者) 定义更新接口,接收主题通知。

  • ConcreteObserver(具体观察者) 实现Observer接口,根据主题的状态变化执行具体操作。


  • 三、观察者模式的代码实现

    1.简单聊天系统示例

    ⑴.Subject(主题接口)

    // 主题接口
    interface ChatRoom {
    void registerUser(User user);
    void removeUser(User user);
    void sendMessage(String message);
    }

    ⑵.Observer(观察者接口)

    // 观察者接口
    interface User {
    void receiveMessage(String message);
    }

    ⑶.ConcreteSubject(具体主题:聊天室)

    // 具体主题:聊天室
    class GroupChat implements ChatRoom {
    private List<User> users = new ArrayList<>();

    @Override
    public void registerUser(User user) {
    users.add(user);
    System.out.println(user + " 加入了聊天");
    }

    @Override
    public void removeUser(User user) {
    users.remove(user);
    System.out.println(user + " 离开了聊天");
    }

    @Override
    public void sendMessage(String message) {
    System.out.println("发送消息: " + message);
    for (User user : users) {
    user.receiveMessage(message);
    }
    }
    }

    ⑷.ConcreteObserver(具体观察者:用户)

    // 具体观察者:用户
    class ChatUser implements User {
    private String name;

    public ChatUser(String name) {
    this.name = name;
    }

    @Override
    public void receiveMessage(String message) {
    System.out.println(name + " 收到消息: " + message);
    }

    @Override
    public String toString() {
    return name;
    }
    }

    ⑸.主类演示

    public class SimpleChatSystem {
    public static void main(String[] args) {
    //创建聊天室
    GroupChat chatroom = new GroupChat();
    //创建用户
    ChatUser zhangsan = new ChatUser("张三");
    ChatUser lisi = new ChatUser("李四");
    ChatUser wangwu = new ChatUser("王五");
    //注册用户到聊天室
    chatroom.registerUser(zhangsan);
    chatroom.registerUser(lisi);
    chatroom.registerUser(wangwu);
    //发送信息
    chatroom.sendMessage("大家好");
    //移除一个用户
    chatroom.removeUser(lisi);
    //再发送一条信息
    chatroom.sendMessage("lisi已经离开");
    }
    }

    运行结果:

    ⑹.代码解释

    ①.核心接口和类

    • ChatRoom 接口:定义了主题的三个核心方法:注册用户、移除用户和发送消息。

    • User 接口:定义了观察者的接收消息方法。

    • GroupChat 类:实现了 ChatRoom 接口,维护一个用户列表,并在有新消息时通知所有用户。

    ②.具体观察者

    • ChatUser 类:实现了 User 接口,当收到消息时会打印消息内容。

    ③.主类演示

    SimpleChatSystem 类:创建了一个 GroupChat 对象和多个 ChatUser 对象,并模拟了消息的发送过程。每次发送消息时,所有注册的用户都会收到通知。

    2.天气预报系统

    假设我们有一个天气预报系统,当天气数据发生变化时,需要通知所有注册的显示设备。

    首先,定义观察者接口:

    // 观察者接口
    public interface Observer {
    void update(float temperature, float humidity, float pressure);
    }

    接下来,定义主题接口:

    // 主题接口
    public interface Subject {
    void registerObserver(Observer o);
    void removeObserver(Observer o);
    void notifyObservers();
    }

    然后,实现具体主题类:

    // 具体主题类
    import java.util.ArrayList;
    import java.util.List;

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

    public WeatherData() {
    observers = new ArrayList<>();
    }

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

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

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

    public void measurementsChanged() {
    notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    measurementsChanged();
    }
    }

    最后,实现具体观察者类:

    // 具体观察者类
    public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
    this.weatherData = weatherData;
    weatherData.registerObserver(this);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
    this.temperature = temperature;
    this.humidity = humidity;
    display();
    }

    public void display() {
    System.out.println("Current conditions: " + temperature
    + "F degrees and " + humidity + "% humidity");
    }
    }

    现在,让我们使用这些类来测试我们的天气系统:

    // 测试类
    public class WeatherStation {
    public static void main(String[] args) {
    WeatherData weatherData = new WeatherData();

    CurrentConditionsDisplay currentDisplay =
    new CurrentConditionsDisplay(weatherData);

    weatherData.setMeasurements(80, 65, 30.4f);
    weatherData.setMeasurements(82, 70, 29.2f);
    weatherData.setMeasurements(78, 90, 29.2f);
    }
    }

    四、Java 内置的观察者模式支持

    Java 提供了内置的观察者模式支持,位于 java.util 包中,包括 Observable 类和 Observer 接口。使用 Java 内置的支持可以简化观察者模式的实现:

    import java.util.Observable;
    import java.util.Observer;

    // 使用Java内置的Observable类
    public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {}

    public void measurementsChanged() {
    setChanged();
    notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
    this.temperature = temperature;
    this.humidity = humidity;
    this.pressure = pressure;
    measurementsChanged();
    }

    public float getTemperature() {
    return temperature;
    }

    public float getHumidity() {
    return humidity;
    }

    public float getPressure() {
    return pressure;
    }
    }

    // 使用Java内置的Observer接口
    public class CurrentConditionsDisplay implements Observer, DisplayElement {
    Observable observable;
    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay(Observable observable) {
    this.observable = observable;
    observable.addObserver(this);
    }

    @Override
    public void update(Observable obs, Object arg) {
    if (obs instanceof WeatherData) {
    WeatherData weatherData = (WeatherData)obs;
    this.temperature = weatherData.getTemperature();
    this.humidity = weatherData.getHumidity();
    display();
    }
    }

    @Override
    public void display() {
    System.out.println("Current conditions: " + temperature
    + "F degrees and " + humidity + "% humidity");
    }
    }

    五、观察者模式的优缺点

    优点:

    • 实现了对象之间的松耦合,主题和观察者可以独立变化和复用。
    • 符合开闭原则,无需修改主题即可增加新的观察者。
    • 支持广播通信,主题可以将通知发送给所有注册的观察者。

    缺点:

    • 如果观察者过多,通知所有观察者可能会影响性能。
    • 观察者可能不知道其他观察者的存在,导致调试困难。
    • 如果主题和观察者之间存在循环依赖,可能会导致系统崩溃。

    六、观察者模式的应用场景

    观察者模式在以下场景中非常有用:

    • 当一个对象的状态变化需要通知其他对象时。
    • 当一个对象需要通知其他对象,而又不希望与这些对象紧密耦合时。
    • 当一个对象的改变需要同时改变其他对象,而不知道具体有多少对象需要改变时。
    • 当一个抽象模型有两个方面,其中一个方面依赖于另一个方面时。

    七、总结

    观察者模式是一种非常实用的设计模式,它提供了一种对象之间的一对多依赖关系,使得当一个对象的状态发生变化时,所有依赖它的对象都会得到通知并自动更新。Java 提供了内置的支持,使得实现观察者模式变得更加简单。在实际开发中,观察者模式被广泛应用于各种场景,如 GUI 事件处理、消息队列、状态管理等。通过合理使用观察者模式,可以使代码更加灵活、可维护和可扩展。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » Java设计模式之观察者模式详解
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!