首页 > 代码库 > 设计模式之观察者模式(Observer)

设计模式之观察者模式(Observer)

1、定义

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

2、问题描述

现在有一个气象站的对象,此对象负责对几个终端输送信息。气象站即可称为主题,而终端即为观察者。气象站和终端是一对多的依赖,当气象站状态改变时,所有终端都会收到通知并启动更新。代码如下:

package observer;/** * 主题 */public interface Subject {    public void registerObServer(Observer o);    public void removeObServer(Observer o);    public void notifyObservers();}
package observer;/** * 观察者 */public interface Observer {    public void update(float temp,float humidity,float pressure);}
package observer;import java.util.ArrayList;public class WeatherData implements Subject{        private ArrayList<Observer> observers;    private float temperature;    private float humidity;    private float pressure;    public  WeatherData(){        observers=new ArrayList<Observer>();    }    public void registerObServer(Observer o) {//注册观察者        observers.add(o);    }    @Override    public void removeObServer(Observer o) {//删除观察者        observers.remove(o);    }    @Override    public void notifyObservers() {        for(Observer ob:observers){            ob.update(temperature, humidity, pressure);        }    }        public void measuermentsChanged(){        notifyObservers();    }        public float getTemperature() {        return temperature;    }    public void setTemperature(float temperature) {        this.temperature = temperature;    }    public float getHumidity() {        return humidity;    }    public void setHumidity(float humidity) {        this.humidity = humidity;    }    public float getPressure() {        return pressure;    }    public void setPressure(float pressure) {        this.pressure = pressure;    }}
package observer;public class CurrentConditionsDisplay implements Observer{    public void update(float temp, float humidity, float pressure) {        System.out.println("current conditions:"+temp);    }}
package observer;public class WeatherStation {    public static void main(String a[]){        WeatherData weatherData=new WeatherData();        Observer currentDisplay=new CurrentConditionsDisplay();        weatherData.setHumidity(12);        weatherData.setPressure(23);        weatherData.setTemperature(344);        weatherData.registerObServer(currentDisplay);        weatherData.measuermentsChanged();    }}

以上完美解决了气象台状态改变后改变其他终端数据的问题。但是这种模式是“推”数据方式,将数据从subject推到observer中。但是有时候终端并不需要所有的状态,终端希望自己主动从subject“拉”数据。在java API中有内置的观察者模式。java.util包内包含最基本的Observer接口和Observable类。可以使用推(push)或拉(pull)的方式传送数据。

使用java API的观察者模式的拉模式,代码如下:

package observer;import java.util.ArrayList;import java.util.Observable;/** * 集成JAVA API中的Observeable(可观察者)类 */public class WeatherData extends Observable{        private float temperature;    private float humidity;    private float pressure;    public  WeatherData(){    }        public void measurementsChanged(){        setChanged();//指示状态已经改变        notifyObservers();//使用拉数据方式    }        public void setMeasuerments(float temperature,float humidity,float pressure){        this.temperature=temperature;        this.humidity=humidity;        this.pressure=pressure;        measurementsChanged();    }        public float getTemperature() {        return temperature;    }    public void setTemperature(float temperature) {        this.temperature = temperature;    }    public float getHumidity() {        return humidity;    }    public void setHumidity(float humidity) {        this.humidity = humidity;    }    public float getPressure() {        return pressure;    }    public void setPressure(float pressure) {        this.pressure = pressure;    }}
package observer;import java.util.Observable;public class CurrentConditionsDisplay implements java.util.Observer{    Observable observable;    private float temperature;    private float humidity;        public CurrentConditionsDisplay(Observable observable){        this.observable=observable;        observable.addObserver(this);    }    @Override    public void update(Observable obs, Object arg) {        if(obs instanceof WeatherData){            WeatherData weatherData=(WeatherData)obs;            this.temperature=weatherData.getTemperature();            this.humidity=weatherData.getHumidity();            System.out.println("Current Conditions:"+this.temperature);        }            }}
package observer;import java.util.Observable;public class WeatherStation {    public static void main(String a[]){        WeatherData weatherData=new WeatherData();        weatherData.setMeasuerments(12,13, 14);        java.util.Observer currentDisplay=new CurrentConditionsDisplay(weatherData);        currentDisplay.update(weatherData, null);    }}

java API中的observable使用类而不是接口,不可取。实际中可以自行设计主题和观察者,不使用java api中提供的方式。

在JDK中,Swing大量使用观察者模式,许多GUI框架也是如此。