甲方提供了一個氣象站的接口,氣象站上面裝有:溫度感應裝置、溼度感應裝置、氣壓感應裝置。編程
如今咱們是乙方,須要設計一個 WeatherData 對象,從氣象站獲取數據,而且利用這些數據,更新三個佈告板(當前情況、氣象統計、天氣預報)。ide
經過簡單地分析,咱們能夠很快肯定一套解決方案:this
WeatherData 提供一個 measurementsChanged() 方法,當這個方法被調用了,去實時獲取氣象站的數據,而後更新到三個佈告板上。spa
public class BadWeatherData { @Getter private float temperature; @Getter private float humidity; @Getter private float pressure; private CurrentConditionsDisplay currentConditionDisplay; private StatisticsDisplay statisticsDisplay; private ForecastDisplay forecastDisplay; public BadWeatherData() { // some initialized function for displays } // We don't care how it be called, we only know is when it is called, we will update displays. public void measurementsChanged() { // We don't care how it gets data float temperature = getTemperature(); float humidity = getHumidity(); float pressure = getPressure(); currentConditionDisplay.update(temperature, humidity, pressure); statisticsDisplay.update(temperature, humidity, pressure); forecastDisplay.update(temperature, humidity, pressure); } }
顯然,這是一個擴展性不好的解決方案,它有以下問題:設計
定義了對象之間的一對多依賴,這樣一來,當一個對象改變狀態時,它的全部依賴者都會收到通知並自動更新。code
觀察者模式 = 主題+觀察者(Subject + Observer)。server
public interface Subject { void registerObserver(Observer observer); void removeObserver(Observer observer); void notifyObservers(); }
public interface Observer { void update(float temperature, float humidity, float pressure); }
public interface DisplayElement { void display(); }
@Data public final class WeatherData implements Subject { private float temperature; private float humidity; private float pressure; private List<Observer> observers = new ArrayList<>(); public void measurementsChanged() { notifyObservers(); } @Override public void registerObserver(Observer observer) { observers.add(observer); } @Override public void removeObserver(Observer observer) { observers.remove(observer); } @Override public void notifyObservers() { observers.forEach(observer -> observer.update(temperature, humidity, pressure)); } }
public class CurrentConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("Current conditions: " + temperature + "F degrees and " + humidity + "% humidity"); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; display(); } }
public class ForecastDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private float pressure; private Subject weatherData; public ForecastDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("Will show forecast related data"); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; display(); } }
public class StatisticsDisplay implements Observer, DisplayElement { private float temperature; private Subject weatherData; public StatisticsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("Statistics will show average temperature"); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; display(); } }