(四)23种设计模式之我见-----------观察者模式(Observer)

来源:互联网 发布:iqr 淘宝网 编辑:程序博客网 时间:2024/06/05 21:51

        设计模式这本书中对观察者模式做了如下定义:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。下面我对深入浅出设计模式这本书中的观察者模式,进行自己的理解性剖析。先贴代码,然后对每段代码进行解析,最后画出完整的类图。观察者模式有两个必须的要素就是主题和观察者。在书中,引用了气象站的例子。我们有一个气象站(获取气象数据),有一个weatherData用来收集气象站的数据,并通知布告板做出更新。还有一个布告板系统用来显示收集到的信息。  

public interface Subject {  public void registerObserver(Observer o);}

我们需要定义一个主题接口,体现了面向接口的编程,而不是具体的实现。然后我们需要接着定义观察者的接口

public interface Observer {   public void update(float temp,float humidity,float pressure);}

        这里需要说明一下主题中,需要有一个方法证明哪些观察者需要被通知,哪些不需要,所以就需要有一个注册方法,类似于一个论坛,你只有注册了,才能享受会员资格。而所有的观察者中就要有一个更新的方法,一旦发生改变就要更新。

        当我们定义一个主题的实现类,用来收集气象站的数据。

import java.util.ArrayList;public class WeatherData implements Subject {private ArrayList observers;private float temperature;private float humidity;private float pressure;        //构造方法中声明了一个ArrayList用来记录所有注册的观察者public WeatherData() {observers = new ArrayList();}        //将观察者加入到其中就是注册public void registerObserver(Observer o) {observers.add(o);}        //删除public void removeObserver(Observer o) {int i = observers.indexOf(o);if (i >= 0) {observers.remove(i);}}        //通知,从ArrayList中取出数据后调用更新方法public void notifyObservers() {for (int i = 0; i < observers.size(); i++) {Observer 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();}// WeatherData的其他方法}

我们有许许多多的观察者,在此例中我们有许许多多的显示面板,需要显示不同的信息,我们定义了三种不同的面板用以显示不同的信息,每一个具体的实现都要保留一个主题的引用。

public class CurrentConditionsDisplay implements Observer, DisplayElement {private float temperature;private float humidity;private Subject weatherData;public CurrentConditionsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver(this);}  public void update(float temperature, float humidity, float pressure) {     this.temperature = temperature;     this.humidity = humidity;     display();}  public void display() {     System.out.println("Current conditions: " + temperature      + "F degrees and " + humidity + "% humidity");}}

public class ForecastDisplay implements Observer,DisplayElement{private float humidity;private Subject weatherData;public ForecastDisplay(Subject weatherData) { this.weatherData = weatherData;  ((WeatherData) weatherData).registerObserver(this);}@Overridepublic void update(float temp, float humidity, float pressure) {this.humidity=humidity;display();}@Overridepublic void display() {if(this.humidity<=65.0){System.out.println("ForeCast : Improving weather on the way!");}else if(this.humidity<=80){        System.out.println("ForeCast : Watch out for cooler,rainy weather!");}else{System.out.println("ForeCast : More of the same!");}}}

public class StatisticsDisplay implements Observer,DisplayElement{private float temperature;private float humidity;private Subject weatherData;public StatisticsDisplay(Subject weatherData) { this.weatherData = weatherData; weatherData.registerObserver( this);}  public void update(float temperature, float humidity, float pressure) {     this.temperature = temperature;     this.humidity = humidity;     display();}  public void display() {  if(this.humidity<=65.0){System.out.println("Avg/Max/Min temperature = 80.0/80.0/80.0");}else if(this.humidity<=80){        System.out.println("Avg/Max/Min temperature = 81.0/82.0/80.0");}else{System.out.println("Avg/Max/Min temperature = 80.0/82.0/78.0");}}}

都实现了observer接口和displayelement接口,以方便weatherdata在具体实现的调用,体现了面向接口编程的优越性。

下面我们要写具体的气象站类用来促使整个过程的发生。

public class WeatherStation {public static void main(String[] args) {   WeatherData weatherData = new WeatherData();   CurrentConditionsDisplay currentDisplay =new CurrentConditionsDisplay(weatherData);   StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);   ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);   weatherData.setMeasurements(80, 65, 30.4f);   weatherData.setMeasurements(82, 70, 29.2f);   weatherData.setMeasurements(78, 90, 29.2f);}}

这样开始我们的神奇之旅吧。我们在每次调用一个观察者的时候就要进行注册,而注册是在构造函数中进行的,所以需要这么写。发动数据只要进行数据的更新操作即可。