设计模式-观察者模式
要理解设计模式中的观察者模式,我们可以从其核心思想入手:定义对象间的一对多依赖关系,当一个对象(主题)的状态发生改变时,所有依赖它的对象(观察者)都会自动收到通知并更新。它的本质是解耦“被观察的主题”和“观察的对象”,让两者可以独立变化,同时确保状态变化能被及时感知。
一、观察者模式的核心角色
观察者模式包含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
三、观察者模式的优点
- 解耦主题与观察者:主题无需知道观察者的具体实现,只需通过接口交互;观察者也可独立增减,不影响主题(符合“开闭原则”)。
- 动态响应变化:主题状态变化时,所有依赖它的观察者会自动收到通知,无需手动触发。
- 灵活扩展:新增观察者只需实现Observer接口并注册,无需修改主题或其他观察者代码。
通过这个例子,我们可以清晰看到:观察者模式通过“一对多”的依赖关系,让主题和观察者实现了松耦合,非常适合“一个对象变化需要联动多个对象响应”的场景(如事件监听、消息订阅、实时数据展示等)。

浙公网安备 33010602011771号