设计模式之观察者模式

来源:互联网 发布:mac文件打包 编辑:程序博客网 时间:2024/05/22 15:23

    某公司有一个气象站应用,有温度、湿度、气压感应装置,我们要做的是实现WeatherData对象,它可以从气象站获得数据并显示,显示方式有三种,对应三种布告板。


首先是一个错误示范:

public class BadWeatherData {//实例变量声明public void measurementsChanged(){float temp=getTemperature();float humidity=getHumidity();float pressure=getPressure();currentConditionsDisplay.update(temp,humidity,pressure);statisticsDisplay.update(temp,humidity,pressure);forecastDisplay.update(temp,humidity,pressure);}//其他方法}

update(temp,humidity,pressure)可以是一个统一的接口,而且针对具体实现编程,会导致我们以后再增加或删除布告板时必须修改程序。改变的地方,需要封装起来。


所以,here comes the observer pattern.观察者模式=出版者(subject)+订阅者(observer)。

观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,他的所有依赖者都会收到通知并自动更新。

它提供了一种对象设计,让主题和观察者之间松耦合


下面实现气象站:

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

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

public interface DisplayElement {public void display();}

在WeatherData中实现subject接口:

import java.util.ArrayList;public class WeatherData implements Subject{private ArrayList observers;private float temperature;private float humidity;private float pressure;public WeatherData(){observers=new ArrayList<>();}@Overridepublic void registerObserver(Observer o) {// TODO Auto-generated method stubobservers.add(o);}@Overridepublic void removeObserver(Observer o) {// TODO Auto-generated method stubint i=observers.indexOf(o);observers.remove(i);}@Overridepublic void notifyObserver() {// TODO Auto-generated method stubfor(int i=0;i<observers.size();i++){Observer observer=(Observer)observers.get(i);observer.update(temperature, humidity, pressure);}}public void measurementsChanged(){notifyObserver();}public void setMeasurements(float temperature,float humidity,float pressure){this.temperature=temperature;this.humidity=humidity;this.pressure=pressure;measurementsChanged();}//其他方法}

建立布告板:


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);}@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("Current conditions:"+temperature+"F degrees and"+humidity+"% humidity");}@Overridepublic void update(float temp, float humidity, float pressure) {// TODO Auto-generated method stubthis.temperature=temp;this.humidity=humidity;display();}}

public class ForecastDisplay implements Observer,DisplayElement{private float temperature;private float humidity;private float pressure;private Subject weatherData;public ForecastDisplay(Subject weatherData){this.temperature=temperature;this.humidity=humidity;this.pressure=pressure;weatherData.registerObserver(this);}@Overridepublic void display() {// TODO Auto-generated method stubif(temperature>80&&humidity>65&&pressure<29.5f)System.out.println("Improving weather on the way");else if(temperature<70&&pressure>30f)System.out.println("Watch out for cooler,rainy weather");else System.out.println("More of the same");}@Overridepublic void update(float temp, float humidity, float pressure) {// TODO Auto-generated method stubthis.temperature=temp;this.humidity=humidity;this.pressure=pressure;display();}}

public class StatisticsDisplay implements Observer,DisplayElement{private float pressure;private Subject weatherData;public StatisticsDisplay(Subject weatherData){this.weatherData=weatherData;weatherData.registerObserver(this);}@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("Pressure  is "+pressure);}@Overridepublic void update(float temp, float humidity, float pressure) {// TODO Auto-generated method stubthis.pressure=pressure;display();}}


启动气象站:

public class WeatherStation {public static void main(String[]args){WeatherData weatherData=new WeatherData();CurrentConditionsDisplay currentConditionsDisplay=new CurrentConditionsDisplay(weatherData);StatisticsDisplay statisticsDisplay=new StatisticsDisplay(weatherData);ForecastDisplay forecastDisplay=new ForecastDisplay(weatherData);weatherData.setMeasurements(90,70,29f);weatherData.setMeasurements(65, 75, 31f);weatherData.setMeasurements(70, 75, 30f);}}


运行程序:

Current conditions:90.0F degrees and70.0% humidityPressure  is 29.0Improving weather on the wayCurrent conditions:65.0F degrees and75.0% humidityPressure  is 31.0Watch out for cooler,rainy weatherCurrent conditions:70.0F degrees and75.0% humidityPressure  is 30.0More of the same


使用Java内置的观察者模式:

java.util包内包含最基本的Observer接口和Observable类。

和以上的实现类似,但有差异,WeatherData现在扩展自Observable类,并继承到一些增加删除通知Observer的方法。


重做气象站:

import java.util.Observable;public class WeatherData extends Observable{private float temperature;private float humidity;private float pressure;public WeatherData(){}public void measurementsChanged(){setChanged();notifyObservers();}public void setMeasurements(float temperature,float humidity,float pressure){this.temperature=temperature;this.humidity=humidity;this.pressure=pressure;measurementsChanged();}public float getTemperature(){return temperature;}public float getHumidity(){return humidity;}public float getPressure(){return pressure;}}

布告栏:

import java.util.Observable;import java.util.Observer;public class CurrentConditionsDisplay implements Observer,DisplayElement{Observable observable;private float temperature;private float humidity;public CurrentConditionsDisplay(Observable observable){this.observable=observable;observable.addObserver(this);}@Overridepublic void display() {// TODO Auto-generated method stubSystem.out.println("Current conditions:"+temperature+"F degrees and"+humidity+"% humidity");}@Overridepublic void update(Observable o, Object arg) {// TODO Auto-generated method stubif(o instanceof WeatherData){WeatherData weatherData=(WeatherData)o;this.temperature=weatherData.getTemperature();this.humidity=weatherData.getHumidity();display();}}}

etc


运行代码:

Improving weather on the wayPressure  is 29.0Current conditions:90.0F degrees and70.0% humidityWatch out for cooler,rainy weatherPressure  is 31.0Current conditions:65.0F degrees and75.0% humidityMore of the samePressure  is 30.0Current conditions:70.0F degrees and75.0% humidity


仔细看会发现输出的次序不一样了。如果我们依赖次序,这样就错了。

所以,java.util.Observable也有局限性,它是一个类不是接口,限制了它的使用和复用。


ps,其实JavaBeans和Swing中,也实现了观察者模式。

0 0