Head First 设计模式--2 观察者模式 解耦
观察者模式定义了对象之间一对多的依赖,这样依赖,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。
假如有这么一个项目,监控每天的天气状况WeatherData(温度,湿度,气压)。有布告板显示天气的不同内容。天气要实时更新,布告板内容也会随着更新。要求可扩展,将来还有可能有别的布告板,WeatherData还有可能添加新内容。
这么一个需要,我们的第一想法就是WeatherData中有三个属性,对应三个获取方法,有几个布告板那就写几个更新方法,在一个大更新方法中分别调用每个布告板的更新方法。
如果这么一写,如果未来又增加了新的布告板,那么就需要在现有的方法中增加这个新的布告板的更新方法,这么一修改了已经写好的代码,那么之前的测试就需要在重新测试一遍。而且这个更新的方法会越来越大,越来越头疼。而且如果有哪个布告板在运行的过程中不想要了,这没法办到。
看一下观察者模式解决这个问题。
直接看代码:
interface Observer { public void update(float temp, float humidity, float preasure); } interface DisplayElement { public void display(); } class CurrentConditionsDisplay implements Observer, DisplayElement { float temperature; float humidity; Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } @Override public void display() { System.out.println("temperature, humidity, pressure is " + temperature + " " + humidity); } @Override public void update(float temp, float humidity, float preasure) { this.temperature = temp; this.humidity = humidity; this.temperature = preasure; } } interface Subject { public void registerObserver(Observer observer); public void removeObserver(Observer observer); public void notifyObserver(); } class WeatherData implements Subject { ArrayList<Observer> observers; float temperature; float humidity; float pressure; public WeatherData() { this.observers = new ArrayList<>(); } @Override public void registerObserver(Observer observer) { this.observers.add(observer); } @Override public void removeObserver(Observer observer) { int i = this.observers.indexOf(observer); if (i > 0) { this.observers.remove(i); } } @Override public void notifyObserver() { for (Observer observer : observers) { observer.update(temperature, humidity, pressure); } } public void measurementsChanged() { notifyObserver(); } public void setMeasurements(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; this.pressure = pressure; measurementsChanged(); } } public class Test { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay display = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 65, 30); display.display(); } }
这里存在的一个问题是三个属性最好封装成一个对象,这样在以后新增其他属性时候方便修改。
一对多的关系:利用观察者模式,主题是一个有状态的对象,并且可以修改这些状态。另一方面,观察者也有一自己的状态,但是观察者的状态使用主题的状态来更新或显示。这样主题与观察者就能有一个一对多的关系。这里,主题是真正拥有对象的人,观察者只是主题的依赖者。
观察者模式提供了一种对象设计,让主题和观察者之间松耦合:
关于观察者的一切,主题只知道观察者实现了某个接口(Observer接口),主题并不需要知道观察者的具体类是谁和其他的细节。想要增加观察者,只需要实现这个接口。运行时,随时增加删除,主题并不会受到影响。我们可以独立的复用主题或者观察者的代码(在类里实现这些接口即可),改变主题或观察者的一方并不会影响到另一方,因为二者并非紧耦合。