设计模式-观察者模式

要理解设计模式中的观察者模式,我们可以从其核心思想入手:定义对象间的一对多依赖关系,当一个对象(主题)的状态发生改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。它的本质是解耦“被观察的主题”和“观察的对象”,让两者可以独立变化,同时确保状态变化能被及时感知。

一、观察者模式的核心角色

观察者模式包含4个核心角色,各自职责如下:

角色 职责描述
主题(Subject) 又称“被观察者”,定义管理观察者的接口(如注册、移除观察者),并声明通知所有观察者的方法。
观察者(Observer) 定义接收主题通知的接口,包含一个更新方法(当主题状态变化时被调用)。
具体主题(ConcreteSubject) 实现主题接口,维护自身状态,当状态变化时,调用通知方法触发所有观察者的更新。
具体观察者(ConcreteObserver) 实现观察者接口,持有对具体主题的引用,在更新方法中根据主题的新状态执行具体逻辑。

二、Java代码演示

我们以“气象站(主题)与显示设备(观察者)”为例(气象站采集天气数据,手机、电视等设备实时显示天气),演示观察者模式的实现。

1. 定义主题接口(Subject)

声明管理观察者和通知的核心方法:

import java.util.ArrayList;
import java.util.List;

// 主题接口(被观察者)
public interface Subject {
    // 注册观察者
    void registerObserver(Observer observer);
    // 移除观察者
    void removeObserver(Observer observer);
    // 通知所有观察者
    void notifyObservers();
}

2. 定义观察者接口(Observer)

声明接收通知后执行的更新方法:

// 观察者接口
public interface Observer {
    // 当主题状态变化时,调用此方法更新
    // 参数:温度、湿度、气压(主题的状态信息)
    void update(float temperature, float humidity, float pressure);
}

3. 定义具体主题(ConcreteSubject)

实现主题接口,维护天气数据状态,状态变化时通知观察者:

// 具体主题:气象站
public class WeatherStation implements Subject {
    private List<Observer> observers; // 观察者列表
    private float temperature; // 温度(状态)
    private float humidity; // 湿度(状态)
    private float pressure; // 气压(状态)

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

    // 更新气象站数据(状态变化)
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        // 数据更新后,通知所有观察者
        notifyObservers();
    }

    @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, pressure);
        }
    }
}

4. 定义具体观察者(ConcreteObserver)

实现观察者接口,根据主题状态执行具体显示逻辑:

// 具体观察者1:手机显示器
public class PhoneDisplay implements Observer {
    // 持有主题引用(可选,用于主动获取状态)
    private Subject weatherStation;

    public PhoneDisplay(Subject weatherStation) {
        this.weatherStation = weatherStation;
        // 注册为观察者
        weatherStation.registerObserver(this);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        // 手机显示逻辑
        System.out.println("【手机显示】天气更新:温度=" + temperature + "℃,湿度=" + humidity + "%,气压=" + pressure + "hPa");
    }
}

// 具体观察者2:电视显示器
public class TVDisplay implements Observer {
    private Subject weatherStation;

    public TVDisplay(Subject weatherStation) {
        this.weatherStation = weatherStation;
        weatherStation.registerObserver(this);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        // 电视显示逻辑(更详细)
        System.out.println("【电视显示】实时天气:\n温度:" + temperature + "℃\n湿度:" + humidity + "%\n气压:" + pressure + "hPa\n");
    }
}

5. 客户端(Client)测试

模拟气象站数据变化,观察观察者的响应:

public class Client {
    public static void main(String[] args) {
        // 1. 创建主题(气象站)
        WeatherStation weatherStation = new WeatherStation();

        // 2. 创建观察者(显示设备)并注册
        new PhoneDisplay(weatherStation);
        TVDisplay tvDisplay = new TVDisplay(weatherStation);

        // 3. 模拟气象站数据更新(第一次)
        System.out.println("--- 第一次天气数据更新 ---");
        weatherStation.setMeasurements(25.5f, 60.0f, 1013.0f);

        // 4. 移除电视观察者
        weatherStation.removeObserver(tvDisplay);
        System.out.println("--- 移除电视显示器后,第二次天气数据更新 ---");

        // 5. 模拟气象站数据更新(第二次)
        weatherStation.setMeasurements(26.0f, 58.0f, 1012.5f);
    }
}

输出结果

--- 第一次天气数据更新 ---
【手机显示】天气更新:温度=25.5℃,湿度=60.0%,气压=1013.0hPa
【电视显示】实时天气:
温度:25.5℃
湿度:60.0%
气压:1013.0hPa

--- 移除电视显示器后,第二次天气数据更新 ---
【手机显示】天气更新:温度=26.0℃,湿度=58.0%,气压=1012.5hPa

三、观察者模式的优点

  1. 解耦主题与观察者:主题无需知道观察者的具体实现,只需通过接口交互;观察者也可独立增减,不影响主题(符合“开闭原则”)。
  2. 动态响应变化:主题状态变化时,所有依赖它的观察者会自动收到通知,无需手动触发。
  3. 灵活扩展:新增观察者只需实现Observer接口并注册,无需修改主题或其他观察者代码。

通过这个例子,我们可以清晰看到:观察者模式通过“一对多”的依赖关系,让主题和观察者实现了松耦合,非常适合“一个对象变化需要联动多个对象响应”的场景(如事件监听、消息订阅、实时数据展示等)。

posted @ 2025-11-05 09:40  fishyy  阅读(11)  评论(0)    收藏  举报