设计模式之观察者模式

观察者模式(Observer Pattern)

观察者模式定义了对象之间的一对多依赖,当一个对象的状态改变时,它的所有依赖者都会收到通知并自动更新。该模式可以让主题和观察者之间松耦合,降低相互之间的依赖性。
一个来自《Head First设计模式》的气象站实例


/*
 * 一个Subject接口(主题接口):让实现该接口的所有类都具有以下三种方法,用于注册、删除、更新观察者
 *
 */
public interface Subject {
    //注册一个观察者
    public void registerObserver(Observer ob);
    //注销一个观察者
    public void removeObserver(Observer ob);
    //当主题状态改变时,调用此方法,更新所有观察者
    public void notifyObservers();
}

/*
 * 一个Observer接口(观察者接口):实现该接口的类必须含有update()方法
 *
 */
public interface Observer {
    //当气象观测值改变时,主题接口的实现类会把这些状态值作为参数传递给Observer接口实现类的update()方法
    public void update(float temperature, float humidity, float pressure);
}

/*
 * 一个DiaplayElement接口
 */
public interface DisplayElement {
    //用于显示天气信息
    public void display();
}

public class WeatherData implements Subject {

    //天气信息的三个属性
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    private List obs;

    //构造方法
    public WeatherData() {
        obs = new ArrayList();//创建一个Observer集合
    }

    //天气信息设置
    public void setData(float temperature, float humidity, float pressure) {
        //为三个属性赋值
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        changeWeather();//天气信息更改时调用方法
    }

    //天气信息更改时,更新观察者
    public void changeWeather() {
        notifyObservers();
    }

    @Override
    public void registerObserver(Observer ob) {
        if(!obs.contains(ob)) {
            obs.add(ob);
        }
    }

    @Override
    public void removeObserver(Observer ob) {
        if(obs.contains(ob)) {
            obs.remove(ob);
        }
    }

    @Override
    public void notifyObservers() {
        for(Observer ob : obs) {
            ob.update(temperature, humidity, pressure);
        }
    }

    //WeatherData的其他方法。。。
}

/*
 * 一个CurrentConditionsDisplay类实现Observer接口和DisplayElement接口:现实中可以有很多种CurrentConditionsDisplay类
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData; 

    //无参构造方法
    public CurrentConditionsDisplay(){}

    //有参的构造方法:在创建CurrentConditionsDisplay的对象时,传入Subject接口实现类,调用实现类的registerObserver()方法,将观察者类注册进去
    public CurrentConditionsDisplay(Subject subject) {
        this.weatherData = subject;
        weatherData.registerObserver(this);
    }

    //注销观察者
    public void removeObserver() {
        weatherData.removeObserver(this);
    }

    @Override
    public void display() {
        System.out.println("今天的天气情况: 温度为" + temperature + "\t湿度为" + humidity + "\t气压为" + pressure);
    }

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        display();      
    }

}

Java内置的观察者模式

让观察者类实现java.util包中的Observer接口,让可观察者继承java.util包中的Observable类
修改过后的代码如下


public class WeatherData extends Observable {

    //天气信息的三个属性
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    //无参的构造方法
    public WeatherData() {}

    public void changeWeather() {
        setChanged();//标记状态已经改变的事实,只有调用此方法时,才会去更新观察者
        notifyObservers();
    }

    //天气信息设置
    public void setData(float temperature, float humidity, float pressure) {
        //为三个属性赋值
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        changeWeather();//天气信息更改时调用方法
    }

    //生成get方法
    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

}

/*
 * 一个DiaplayElement接口
 */
public interface DisplayElement {
    //用于显示天气信息
    public void display();
}

public class CurrentConditionsDisplay implements DisplayElement, Observer {

    private Observable observable;
    //天气信息的三个属性
    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    //无参构造方法
    public CurrentConditionsDisplay() {}

    //有参构造方法
    public CurrentConditionsDisplay(Observable obs) {
        this.observable = obs;
        observable.addObserver(this);
    }

    @Override
    public void update(Observable o, Object arg) {
        if(o instanceof WeatherData) {
            WeatherData weatherData = (WeatherData) o;
            this.temperature = weatherData.getTemperature();
            this.humidity = weatherData.getHumidity();
            this.pressure = weatherData.getPressure();
            display();
        }
    }

    @Override
    public void display() {
        System.out.println("今天的天气情况: 温度为" + temperature + "\t湿度为" + humidity + "\t气压为" + pressure);
    }

}

注意:setChanged()方法。使用Java内置的观察者模式有个缺陷就是,可观察者是继承Observable类,如果可观察者已经继承其他父类,则无法实现观察者模式,由于Java中不支持多继承,因此,在使用该模式时,要视情况而定。

你可能感兴趣的:(设计模式之观察者模式)