看过直播的同学都知道,直播房间里有个订阅按钮,当你点击订阅之后,下次主播再开播时你就能在第一时间收到通知,以免你错过精彩内容。这就是观察者模式的一种经典应用。
示例程序 场景 假设我们有一个记录天气的气象站,它会收集湿度、温度、气压这三个天气数据,需要在不同类型的显示装置中展示天气。如下图所示
现在我们有一个记录天气变化的类 WeatherData。还有不同类型的显示装置类 FullConditionsDisplay 和 PartConditionsDisplay。
类结构图
Observer 1 2 3 public interface Observer { public void update(float temperature, float humidity, float pressure); }
Subject 1 2 3 4 5 6 public interface Subject { public void addObserver(Observer o); public void removeObserver(Observer o); public void notifyObservers(); }
DisplayElement 1 2 3 public interface DisplayElement { public void display(); }
天气 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 public class WeatherData implements Subject { private ArrayList<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<>(); } @Override public void addObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { observers.remove(o); } @Override public void notifyObservers() { for (int i = 0; i < observers.size(); i++) { Observer observer = observers.get(i); observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } }
观察者 1 号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 //展示全部的天气数据。 public class FullConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private float pressure; private Subject weatherData; public FullConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.addObserver(this); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; display(); } @Override public void display() { System.out.println("full conditions:: temperature:" + temperature + "\t humidity:" + humidity + "\t pressure:" + pressure); } }
观察者 2 号 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 //展示部分天气数据。(温度和湿度) public class PartConditionsDisplay implements Observer, DisplayElement { private float temperature; private float humidity; private Subject weatherData; public PartConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.addObserver(this); } @Override public void update(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = pressure; display(); } @Override public void display() { System.out.println("part conditions:" + temperature + "F degrees and " + humidity + "% humidity."); } }
Main 1 2 3 4 5 6 7 8 9 10 public class Main { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); PartConditionsDisplay partConditionsDisplay = new PartConditionsDisplay(weatherData); FullConditionsDisplay fullConditionsDisplay = new FullConditionsDisplay(weatherData); weatherData.setMeasurements(80, 65, (float) 30.44); weatherData.setMeasurements(75, 70, (float) 38.44); } }
运行结果
github 代码地址
扩展
JDK 内置了 Observer 模式,但是却在 JDK9 之后将其标记为 @Deprecated,为什么呢?
Observable 被定义成一个类,而不是接口。由于 Java 是单继承的,JDK 内置的实现不够灵活(比如你还想额外继承一个自己的类),无法满足特定场景。
Observable 没有实现 Serializable 接口,无法进行序列化,导致其无法适用于网络编程。
既然如此,有能替代它的吗?有,在 java.beans 包中。
PropertyChangeListener(Observer)。
PropertyChangeSupport(Observable)。
引用