1. 模式定义
观察者模式(Observer Pattern)定义了对象之间的一对多依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都会得到通知并自动更新。
2. 核心组件
2.1 Subject(主题/被观察者)
java
public interface Subject {
void registerObserver(Observer observer); // 注册观察者
void removeObserver(Observer observer); // 移除观察者
void notifyObservers(); // 通知所有观察者
}
2.2 Observer(观察者)
java
public interface Observer {
void update(Object data); // 接收更新通知
}
3. 完整实现示例
3.1 具体主题类
java
import java.util.*;
public class WeatherStation implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherStation() {
observers = new ArrayList<>();
}
@Override
public void registerObserver(Observer observer) {
observers.add(observer);
System.out.println("观察者已注册");
}
@Override
public void removeObserver(Observer observer) {
observers.remove(observer);
System.out.println("观察者已移除");
}
@Override
public void notifyObservers() {
WeatherData data = new WeatherData(temperature, humidity, pressure);
for (Observer observer : observers) {
observer.update(data);
}
}
// 天气数据改变时调用
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
private void measurementsChanged() {
notifyObservers();
}
// 天气数据类
public static class WeatherData {
private final float temperature;
private final float humidity;
private final float pressure;
public WeatherData(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
}
// getters
public float getTemperature() { return temperature; }
public float getHumidity() { return humidity; }
public float getPressure() { return pressure; }
}
}
3.2 具体观察者类
java
// 当前天气显示板
public class CurrentConditionsDisplay implements Observer {
private String name;
public CurrentConditionsDisplay(String name) {
this.name = name;
}
@Override
public void update(Object data) {
if (data instanceof WeatherStation.WeatherData) {
WeatherStation.WeatherData weatherData = (WeatherStation.WeatherData) data;
display(weatherData);
}
}
private void display(WeatherStation.WeatherData data) {
System.out.println(name + " - 当前天气:");
System.out.println("温度:" + data.getTemperature() + "°C");
System.out.println("湿度:" + data.getHumidity() + "%");
System.out.println("气压:" + data.getPressure() + " hPa");
System.out.println("------------------------");
}
}
// 统计显示板
public class StatisticsDisplay implements Observer {
private List<Float> temperatures = new ArrayList<>();
@Override
public void update(Object data) {
if (data instanceof WeatherStation.WeatherData) {
WeatherStation.WeatherData weatherData = (WeatherStation.WeatherData) data;
temperatures.add(weatherData.getTemperature());
display();
}
}
private void display() {
float avg = (float) temperatures.stream().mapToDouble(Float::doubleValue).average().orElse(0);
float max = temperatures.stream().max(Float::compare).orElse(0f);
float min = temperatures.stream().min(Float::compare).orElse(0f);
System.out.println("温度统计:");
System.out.println("平均温度:" + String.format("%.1f", avg) + "°C");
System.out.println("最高温度:" + max + "°C");
System.out.println("最低温度:" + min + "°C");
System.out.println("------------------------");
}
}
4. 使用示例
java
public class WeatherStationDemo {
public static void main(String[] args) {
// 创建天气站
WeatherStation weatherStation = new WeatherStation();
// 创建观察者
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay("显示板1");
CurrentConditionsDisplay currentDisplay2 = new CurrentConditionsDisplay("显示板2");
StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
// 注册观察者
weatherStation.registerObserver(currentDisplay);
weatherStation.registerObserver(currentDisplay2);
weatherStation.registerObserver(statisticsDisplay);
// 更新天气数据
System.out.println("=== 第一次天气更新 ===");
weatherStation.setMeasurements(25.5f, 65f, 1013.2f);
System.out.println("\n=== 第二次天气更新 ===");
weatherStation.setMeasurements(28.0f, 70f, 1012.8f);
// 移除一个观察者
weatherStation.removeObserver(currentDisplay2);
System.out.println("\n=== 第三次天气更新(移除显示板2后) ===");
weatherStation.setMeasurements(22.3f, 60f, 1014.1f);
}
}