7. 观察者(Observer)

Intent

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

设计模式 - 观察者 - 图1

Class Diagram

主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。

观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。

设计模式 - 观察者 - 图2

Implementation

天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。

设计模式 - 观察者 - 图3

  1. public interface Subject {
  2. void registerObserver(Observer o);
  3. void removeObserver(Observer o);
  4. void notifyObserver();
  5. }
  1. public class WeatherData implements Subject {
  2. private List<Observer> observers;
  3. private float temperature;
  4. private float humidity;
  5. private float pressure;
  6. public WeatherData() {
  7. observers = new ArrayList<>();
  8. }
  9. public void setMeasurements(float temperature, float humidity, float pressure) {
  10. this.temperature = temperature;
  11. this.humidity = humidity;
  12. this.pressure = pressure;
  13. notifyObserver();
  14. }
  15. @Override
  16. public void registerObserver(Observer o) {
  17. observers.add(o);
  18. }
  19. @Override
  20. public void removeObserver(Observer o) {
  21. int i = observers.indexOf(o);
  22. if (i >= 0) {
  23. observers.remove(i);
  24. }
  25. }
  26. @Override
  27. public void notifyObserver() {
  28. for (Observer o : observers) {
  29. o.update(temperature, humidity, pressure);
  30. }
  31. }
  32. }
  1. public interface Observer {
  2. void update(float temp, float humidity, float pressure);
  3. }
  1. public class StatisticsDisplay implements Observer {
  2. public StatisticsDisplay(Subject weatherData) {
  3. weatherData.reisterObserver(this);
  4. }
  5. @Override
  6. public void update(float temp, float humidity, float pressure) {
  7. System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
  8. }
  9. }
  1. public class CurrentConditionsDisplay implements Observer {
  2. public CurrentConditionsDisplay(Subject weatherData) {
  3. weatherData.registerObserver(this);
  4. }
  5. @Override
  6. public void update(float temp, float humidity, float pressure) {
  7. System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
  8. }
  9. }
  1. public class WeatherStation {
  2. public static void main(String[] args) {
  3. WeatherData weatherData = new WeatherData();
  4. CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
  5. StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);
  6. weatherData.setMeasurements(0, 0, 0);
  7. weatherData.setMeasurements(1, 1, 1);
  8. }
  9. }
  1. CurrentConditionsDisplay.update: 0.0 0.0 0.0
  2. StatisticsDisplay.update: 0.0 0.0 0.0
  3. CurrentConditionsDisplay.update: 1.0 1.0 1.0
  4. StatisticsDisplay.update: 1.0 1.0 1.0

JDK

设计模式 - 观察者 - 图4