设计模式之观察者模式

来源:互联网 发布:足球球员数据网站 编辑:程序博客网 时间:2024/05/22 15:27

    观察者模式其定义了对象之间的一对多的依赖关系,这样一来,当一个对象改变时他所有的依赖者都会收到通知,并得知后自动更新,好比猎头与求职者的关系,猎头会把求职这的信息添加到自己的人员名单中,当有招聘信息时就会通知名单中所有的人,每个人类似于一个对象,当猎头对象改变时,名单中的每个人都会改变状态。这种观察者模式实线的方式不只有一种,但是包括Subject和Observer接口的类的设计的做法是最常见的。因为主题是真正用于数据的人,在数据变化更新时,这样比起许多对象控制同一份数据来,可以得到更干净的OO设计。

     设计类图如下:



    通过一个案例来实现这个设计模式:

        案例背景:一个气象服务公司,当采集的气象数据发生变化,对应的其它的显示平台上的数据也应该做出相应的变化,例如,电子布告板,手机软件等;对此,我们采用上述的观察者设计模式来进行设计:



根据类图首先设计接口:

public interface Subject{public void registerObserver(Observer o);public void removeObserver(Observer o);public void notifyObservers();}public interface Observer{public void update(float temp,float humity,float pressure);}public interface DisplayElement{public void display();}
之后在,WeatherData中实现主题接口:
public class WeatherData implements Subject {private ArrayList observers;private float temperature;private float humidity;private float pressure;public WeatherData(){observers = new ArrayList();}public void registerObserver(Observer o){observer.add(o);}public void removeObserver(Observer o){int i = observers.indexOf(o);if(i >= 0){observers.remove(i);}}public void notifyObservers(){for (int i = 0;i<observers.size() ;i++ ){Observer observer = (Observer)obervers.get(i);observer.update(temperature,humidity,pressure);}}public void measurementChanged(){notifyObservers();}public void setMeasurements(float temperature,float humidity,float pressure){this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;measurementChanged();}//其它方法}
对应类图,我们实现一个布告板,同样的例如StatisticPlay类也可以仿照这个类进行设计:

public class CurrentConditionDisplay implements Observer,DisplayElement{private float temperature;private float humidity;private Subject weatherData;public CurrentConditionDisplay(Subject weatherData){this.weatherDta = 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 WeatherStation{public static void main(String[] args){WeatherData weatherData = new WeatherData();CurrentConditionDisplay currentDisplay = new CurrentConditionDisplay(weatherData);StatisticDisplay statisticDispaly = new StatisticPlay(weatherData);weatherData.setMeasurements(80,65,30.4f);weatherData.setMeasurements(70,69,33.4f);weatherData.setMeasurements(60,64,32.4f);}}
测试结果如下:


2.使用Java内置的Observer接口来实现:

Java API 有内置的观察者模式,其java.util包中包含了最基本的Observer接口和Oberserable类,这个和上面所说的SUbject接口和Observer很相似,很多功能已经实现,这样我们也能够实现主动推送的方式,当然呢,也可使用使用时再去获取的方式。重新设计的类图如下:



观察者对象的增加减少等可以通过Observerable类里面内置的方法来操作对象是否为观察者对象,其次,主题状态的则可以通过setChanged()方法将改变的事实进行标记,在通过调用notifyObservers() 或者是notifyObservers(Object arg)来进行通知。观察者的变化则体现在update()方法上,方法的签名做了变化,添加了两个参数(Observer o,Object arg),如果想使用主动推送的方式,则可以调用notifyObservers(Object arg)来实现数据的互动更新,其次,若调用不带参数的notifyObservers()方法,则即默认为通过拉的方式实现数据更新的操作,WeatherData类(自动获取数据的方式)重新实现如下:

import java.util.Observerable;import java.util.Observer;public class WeatherData extends Observerable{private float temperature;private float humidity;private float pressure;public WeatherData(){}public void measurementChanged(){setChanged();notifyObservers();}public void setMeasurements(float temperature,float humidity,float pressure){this.temperature = temperature;this.humidity = humidity;this.pressure = pressure;measurementChanged();}public float getTemperature(){return temperature;}public float getHumidity(){return humidity;}public float getPressure(){return pressure;}}
    CurrentConditionalDisplay类重新设计如下:

import java.util.Observerable;import java.util.Observer;public class CurrentConditionDisplay implements Observer,DisplayElement{private float temperature;private float humidity;Oberserable observerable;public CurrentConditionDisplay(Oberserable observerable){this.observerable = observerable;weatherData.registerObserver(this);}public void update(Oberserable obs,Object arg){if( obs instanceof WeatherData){WeatherData weatherData = (WeatherData)obs;this.temperature = weatherData.getTemperature();this.humidity = weatherData.getHumidity();}display();}public void display(){System.out.println("Current conditions: " + temperature +"F degrees and " + humidity + "% humidity");}}

运行结果如下:



notifyObservers()方法并不能够依赖于被通知者的次序,如果代码以来这样的次序,就是错的,因为一旦观察者/主题的实线有所改变,通知次序就会改变,很可能就会产生错误的结果,这绝对不是我i们所认为的松耦合。

     如果仔细观察的话,Observerable是一个类,这是一个缺点,限制于类,则限制了它的复用,设计的时候必须继承这个类,如果某个类想同时具有多个Observerable类和另一个超类的行为,就会陷入两难的境地,毕竟java不支持多重继承,这就限制了Observerable服用的潜力。同时,通过API可以得知,setChanged()方法被保护起来了,(protected)这就意味着必须要继承这个类,否则无法创建实例病组合到自己的对象之中。如果想解决这个问题的话,可以参考1的方法,自己定义这个模式,即可解决Observerable类不可复用的限制。







    

原创粉丝点击