假如咱们有一个开发需求——建造一个气象观测站展现系统。需求方给咱们提供了一个WeatherObject对象,可以自动得到最新的测量数据。而咱们要创建一个应用,有三种布告版,分别显示目前的情况,气象统计,简单预报。三种布告板能即时显示WeatherObject对象中更新的数据。java
同时,咱们须要这是一个可扩展的气象站,能够公布一组api,好让其余开发人员写出本身的布告板插入此应用中。编程
咱们首先来看看咱们的大体系统框架设计模式
咱们的工做就算创建一个应用,利用weatherData对象取得数据,并更新布告板。api
根据weatherData源文件,咱们的工做是实现measurementChanged(),当测量数据备妥时,measurementChanged()方法将会被调用。框架
先来看一个可能的实现,ide
很明显,这个实现并不稳当。回想第一章的OO原则,会发现咱们在针对具体实现编程,这会致使当有新需求时咱们必须修改程序。同时,更新布告板的代码会常常改变,咱们应该尽量将其封装。this
接下来咱们将应用观察者模式来改进现有设计。设计
以报纸订阅为例,咱们像某家报社订阅报纸,只要他们有新报纸第一版,就会给派送给订户。而订户不想要了,就能够取消订阅。只要报社还在运营,就不断有人订阅或者取消订阅报纸。code
出版者+订阅者=观察者模式server
若是了解了报纸订阅是怎么回事,观察者模式也大致如此。出版者即为观察者模式中的主题(Subject),订阅者即为观察者模式中的观察者(Observer)。
定义观察者模式
观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的全部依赖着都会收到通知并自动更新。
类图如图所示
观察者模式提供了一种对象设计,让主题和观察者之间松耦合。
对于观察者,主题只关心观察者实现了Observer接口,主题并不关心观察者的细节。
任什么时候候均可以新增观察者,由于主题惟一以来的东西是一个实现了Observer接口的对象列表,同时,也能够在任什么时候候删除观察者。
改变主题或观察者中的其中一方,并不会影响到另外一方。
设计原则
设计应该尽量下降交互对象之间的耦合度
依照观察者模式,获得咱们的新设计
当前,咱们暂时不用Java内置的观察者模式,而是本身实现这部分代码。
public interface Observer { public void update(float temp,float humidity,float pressure); }
public interface Subject { public void notifyObserver(); public void removeObserver(Observer observer); public void registerObserver(Observer observer); }
public interface DisplayElement { public void display(); }
import java.util.ArrayList; import java.util.List; public class WeatherData implements Subject { private List<Observer> Observers; private float temperature; private float humidity; private float pressure; public WeatherData() { Observers = new ArrayList<Observer>(); } @Override public void notifyObserver() { for (Observer o: Observers ) { o.update(temperature,humidity,pressure); } } @Override public void removeObserver(Observer observer) { Observers.remove(observer); } @Override public void registerObserver(Observer observer) { Observers.add(observer); } public void measurementChanged() { notifyObserver(); } public void setMeasurements(float temperature,float humidity,float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; measurementChanged(); } }
public class CurrentConditionsDisplay implements Observer,DisplayElement{ private float temperature; private float humidity; private Subject weatherData; @Override public void display() { System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity"); } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; display(); } public CurrentConditionsDisplay( Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this); } }
public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80,65,30.4f); } }
使用Java内置的观察者模式
Java api有自带的观察者模式,包含Observer接口和Observable类,在使用上更加方便,不少功能已经事先准备好了。以下是咱们使用Java内置观察者模式修改后的设计。
注册/删除观察者
调用Observable对象的addObserver方法和deleteObserver方法便可
被观察者送出通知
首先调用setChanged()方法,标记状态已经改变,后调用notifyObservers(),那么全部观察者都会调用自身的update方法。
import java.util.Observable; import java.util.Observer; public class CurrentConditionsDisplay implements Observer,DisplayElement{ private double temperature; private double humidity; private Observable observable; @Override public void display() { System.out.println("Current temperature "+temperature+"F degrees and "+humidity+"%humidity"); } public CurrentConditionsDisplay(Observable observable) { this.observable = observable; observable.addObserver(this); } @Override public void update(Observable o, Object arg) { if(o instanceof WheatherData) { temperature = ((WheatherData) o).getTemperature(); humidity = ((WheatherData) o).getHumidity(); display(); } } }
import java.util.ArrayList; import java.util.List; import java.util.Observable; public class WheatherData extends Observable { private double temperature; private double humidity; private double pressure; public double getHumidity() { return humidity; } public double getPressure() { return pressure; } public double getTemperature() { return temperature; } public void setMeasurements(double temperature,double humidity,double pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; setChanged(); notifyObservers(); } }
不幸的是,observable是一个类而不是接口,致使咱们难以继承其余类,同时也没法拥有本身独特的实现。
在实际使用时,咱们须要权衡是使用jdk自带的观察者模式亦或是由本身实现。