观察者模式 观察者模式:定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。 上面是书中对观察者模式的定义。从定义中我们大体可以读懂这个模式的基本思想:一个对象状态改变,会通知依赖(订阅它的对象)它的所有对象。这就好比我们生活中的报纸订阅模式: 1) 报社的业务就是出版报纸。 2) 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。 3) 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。 4) 只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消订阅报纸。 你可以这样理解: 出版者 + 订阅者 = 观察者模式 其中的出版者在模式中称为【主题】(Subject),订阅者改称为【观察者】Observer。如图1所示: Figure 1 主题订阅图 实现观察者模式的方法不只一种,但是以包含Subject与Observer接口的 类设计的做法最常见。下面我们基于接口来说明观察者模式,类图如图2所示:
Figure 2观察者模式类图 从上图我们可以知道,这种设计可以使两者实现松耦合。因为,关于观察者的一切,主题只知道观察者实现了某个接口(Observer接口)。主题不需要知道观察者的具体实现类是谁、做了些什么等。如果我们要增加新的观察者,只需要新增的观察者实现了该接口,并注册到主题中即可。 下面我们拿书中的例子来具体说明: 现有一个气象站会实时抓取天气的相关信息,比如温度、湿度、气压等,现在要建一些公告板来分别显示这些信息,具体如下图3所示:
Figure 3气象参数图 图中的WeatherData对象负责跟踪这些气象数据,具体如何跟踪这里跟我们无关,它取得最新数据会更新自己的状态。之后相关的公告板会实时的显示这些信息。那么这显然是一个观察者模式的相关例子,WeatherData—Subject , 公告板—Observer。代码如下所示: //Subject
//WeatherData
/** * @ClassName: WeatherData * @Description: Subject 具体的实现类 * @author 春天画花卉校长 * @date 2017年2月19日 下午11:52:50 * */public class WeatherData implements Subject{ PRivate ArrayList<Observer> observers; private float temperature; private float humidity; private float pressure; public WeatherData() { observers = new ArrayList<Observer>(); } @Override public void registerObserver(Observer o) { observers.add(o); } @Override public void removeObserver(Observer o) { int i = observers.indexOf(o); if (i >= 0) { 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() { this.notifyObservers(); } public void setMeasurements(float temperature, float humidity, float pressure) { this.temperature = temperature; this.humidity = humidity; this.pressure = pressure; this.measurementsChanged(); }}//Observer
/** * @ClassName: Observer * @Description: Observer Interface* @author 春天画花卉校长 * @date 2017年2月19日 下午11:45:04 * */public interface Observer { //所有观察者都必须实现update()方法,以实现观察者接口。当气象值改变时,主题会把这些状态当作参数,推给观察者 public void update(float temp, float humidity, float pressure);}//CurrentConditionsDisplay
/** * @ClassName: CurrentConditionsDisplay * @Description: Observer 具体的实现类 * @author 春天画花卉校长 * @date 2017年2月20日 上午12:00:01 * */public class CurrentConditionsDisplay implements Observer { private float temperature; private float humidity; private Subject weatherData; public CurrentConditionsDisplay(Subject weatherData) { super(); this.weatherData = weatherData; weatherData.registerObserver(this);//构造器需要weatherData对象作为注册之用 } public CurrentConditionsDisplay() { } @Override public void update(float temp, float humidity, float pressure) { this.temperature = temp; this.humidity = humidity; System.out.println("Current conditions:" + temperature + "F degrees and " + humidity + "% humidity."); }}//Main
/** * @ClassName: WeatherStation * @Description: 测试主类* @author 春天画花卉校长 * @date 2017年2月20日 上午12:04:31 * */public class WeatherStation { public static void main(String[] args) { WeatherData weatherData = new WeatherData(); CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData); weatherData.setMeasurements(80, 79, 30.4f); }}//运行结果 其实在java API有内置的观察者模式。Java.util包(Package)内包含最基本的Observer接口与Observable类,这和Subject接口和Observer接口很相似。甚至对消息的通知提供了推和拉两种模式,推就是主题会把所有的数据都给观察者,而拉则是有观察者自己去拉取自己所要的数据。 在Observable类中基本的对观察者的增、删、通知观察者的方法都已经实现,你所要做的就是继承这个类。
新闻热点
疑难解答