在观察者设计模式中,一个对象(被观察者)维护一系列依赖于它的对象(观察者),当被观察者的状态发生变化时,它会通知所有的观察者。使用观察者模式可以实现解耦,被观察者不需要关心观察者的具体实现,观察者只需注册到被观察者即可。
场景描述:
我们可以将一个气象站作为"被观察者"(WeatherStation
),它会定期检测温度、湿度和气压。多个显示面板作为"观察者"(Observer
),当气象站更新天气信息时,所有的观察者都会收到通知并显示最新数据。
代码实现
1. 定义 Subject
接口(被观察者)
java
import java.util.ArrayList;
import java.util.List;
interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObservers();
}
2. 定义 Observer
接口(观察者)
java
interface Observer {
void update(float temperature, float humidity, float pressure);
}
3. 实现 WeatherStation
类(具体的被观察者)
java
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 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 setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
measurementsChanged();
}
public void measurementsChanged() {
notifyObservers();
}
}
4. 实现具体的观察者类
4.1 CurrentConditionsDisplay
(当前天气显示面板)
java
class CurrentConditionsDisplay implements Observer {
private float temperature;
private float humidity;
@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 + "C degrees and " + humidity + "% humidity.");
}
}
4.2 StatisticsDisplay
(天气统计显示面板)
java
class StatisticsDisplay implements Observer {
private float maxTemp = 0.0f;
private float minTemp = 200;
private float tempSum = 0.0f;
private int numReadings;
@Override
public void update(float temperature, float humidity, float pressure) {
tempSum += temperature;
numReadings++;
if (temperature > maxTemp) {
maxTemp = temperature;
}
if (temperature < minTemp) {
minTemp = temperature;
}
display();
}
public void display() {
System.out.println("Avg/Max/Min temperature = " + (tempSum / numReadings) + "/" + maxTemp + "/" + minTemp);
}
}
4.3 ForecastDisplay
(天气预报显示面板)
java
class ForecastDisplay implements Observer {
private float currentPressure = 29.92f;
private float lastPressure;
@Override
public void update(float temperature, float humidity, float pressure) {
lastPressure = currentPressure;
currentPressure = pressure;
display();
}
public void display() {
System.out.print("Forecast: ");
if (currentPressure > lastPressure) {
System.out.println("Improving weather on the way!");
} else if (currentPressure == lastPressure) {
System.out.println("More of the same");
} else if (currentPressure < lastPressure) {
System.out.println("Watch out for cooler, rainy weather");
}
}
}
5. 测试代码
java
public class WeatherStationDemo {
public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();
CurrentConditionsDisplay currentDisplay = new CurrentConditionsDisplay();
StatisticsDisplay statisticsDisplay = new StatisticsDisplay();
ForecastDisplay forecastDisplay = new ForecastDisplay();
// 注册观察者
weatherStation.registerObserver(currentDisplay);
weatherStation.registerObserver(statisticsDisplay);
weatherStation.registerObserver(forecastDisplay);
// 模拟气象站数据变化
weatherStation.setMeasurements(28, 65, 30.4f);
weatherStation.setMeasurements(27, 70, 29.2f);
weatherStation.setMeasurements(26, 90, 29.2f);
}
}
输出结果
plaintext
Current conditions: 28.0C degrees and 65.0% humidity.
Avg/Max/Min temperature = 28.0/28.0/28.0
Forecast: Improving weather on the way!
Current conditions: 27.0C degrees and 70.0% humidity.
Avg/Max/Min temperature = 27.5/28.0/27.0
Forecast: Watch out for cooler, rainy weather
Current conditions: 26.0C degrees and 90.0% humidity.
Avg/Max/Min temperature = 27.0/28.0/26.0
Forecast: More of the same
代码解释
- Subject接口 :
WeatherStation
实现了Subject
接口,负责维护观察者列表并通知所有观察者。 - Observer接口 :不同的显示面板实现了
Observer
接口,每当气象站数据更新时,这些观察者会自动收到通知。 - WeatherStation类:当气象站的测量数据(温度、湿度、气压)发生变化时,会通知所有注册的观察者。
- Observer实现类 :
CurrentConditionsDisplay
、StatisticsDisplay
和ForecastDisplay
是具体的观察者,它们在接收到通知后会更新自己的显示内容。
总结
观察者模式很好地解耦了数据源(气象站)和观察者(显示面板)。通过这种模式,当气象站的数据变化时,所有观察者都会自动收到通知并更新显示,扩展性好且易于维护。