设计模式——观察者模式

观察者模式面向的需求是:

        A对象(观察者)对B对象(被观察者)的某种变化高度敏感,需要在B变化的一瞬间做出反应。

举个例子,新闻里喜闻乐见的警察抓小偷,警察需要在小偷伸手作案的时候实施抓捕。在这个例子里,警察是观察者、小偷是被观察者,警察需要时刻盯着小偷的一举一动,才能保证不会错过任何瞬间。程序里的观察者和这种真正的【观察】略有不同,观察者不需要时刻盯着被观察者(例如A不需要每隔1ms就检查一次B的状态),二是采用注册(Register)或者成为订阅(Subscribe)的方式告诉被观察者:我需要你的某某状态,你要在它变化时通知我。采取这样被动的观察方式,既省去了反复检索状态的资源消耗,也能够得到最高的反馈速度。


下面的例子是天气更新的观察者模式的实际应用,当天气更新后会通知当前天气的类(CurrentConditionsDisplay)和预测天气的类(ForecastDisplay)。
如果不用观察者模式去实现,观察者可能需要不断的查询 天气类中天气是否变化(比如每秒查询一次)。

观察者接口:
/**
 * 观察者
 */
public interface Observer {

    void update();
}

被观察者接口:

/**
 * 发布者、被观察者
 */

public interface Subject {

    /**
     * 注册观察者
     */
    void registerObserver(Observer observer);

    /**
     * 移除观察者
     */
    void removeObserver(Observer observer);

    /**
     * 通知观察者
     */
    void notifyObservers();
}

用于显示观察者信息的接口,继承观察者的类同时需要继承该类(也可以写在Observer类中):

/**
 * 用于显示观察者信息变化
 */

public interface DisplayElement {
    void display();
}

天气的类(被观察者),当天气数据发生变化时,会通知所有的观察者更新数据:

public class WeatherData implements Subject {

    private List<Observer> observers;

    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压
    private List<Float> forecastTemperatures;//未来几天的温度

    public WeatherData() {
        this.observers = new ArrayList<Observer>();
    }

    @Override
    public void registerObserver(Observer observer) {
        this.observers.add(observer);
    }

    @Override
    public void removeObserver(Observer observer) {
        this.observers.remove(observer);
    }

    @Override
    public void notifyObservers() {
        for (Observer observer : observers) {
            observer.update();
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure, List<Float> forecastTemperatures) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        this.forecastTemperatures = forecastTemperatures;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public List<Float> getForecastTemperatures() {
        return forecastTemperatures;
    }
}
当前天气的类(CurrentConditionsDisplay),该类为天气的观察者。
public class CurrentConditionsDisplay implements Observer, DisplayElement {

    private WeatherData weatherData;

    private float temperature;//温度
    private float humidity;//湿度
    private float pressure;//气压

    public CurrentConditionsDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        this.weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("当前温度为:" + this.temperature + "℃");
        System.out.println("当前湿度为:" + this.humidity);
        System.out.println("当前气压为:" + this.pressure);
    }

    @Override
    public void update() {
        this.temperature = this.weatherData.getTemperature();
        this.humidity = this.weatherData.getHumidity();
        this.pressure = this.weatherData.getPressure();
        display();
    }
}
预测天气的类(ForecastDisplay),该类为天气的观察者。
public class ForecastDisplay implements Observer, DisplayElement {

    private WeatherData weatherData;

    private List<Float> forecastTemperatures;//未来几天的温度

    public ForecastDisplay(WeatherData weatherData) {
        this.weatherData = weatherData;
        this.weatherData.registerObserver(this);
    }

    @Override
    public void display() {
        System.out.println("未来几天的气温");
        int count = forecastTemperatures.size();
        for (int i = 0; i < count; i++) {
            System.out.println("第" + i + "天:" + forecastTemperatures.get(i) + "℃");
        }
    }

    @Override
    public void update() {
        this.forecastTemperatures = this.weatherData.getForecastTemperatures();
        display();
    }
}

以上类的结构关系如下:

 

主程序入口:

   @OnClick(R.id.notifiyObservers) public void onNotifiyObservers(){
        List<Float> futureTemperature = new ArrayList<>();
        futureTemperature.add(2.0f);
        futureTemperature.add(3.0f);

        //构造 被观察者
        WeatherData weatherData = new WeatherData();

        //构造 观察者1,初始话的时候将自身添加到被观察者的对队列中
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
        //构造 观察者1,初始话的时候将自身添加到被观察者的对队列中
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);

        // 被观察者 天气数据发生变化,内部会调用 队列中的观察者update函数
        weatherData.setMeasurements(1,20,200,futureTemperature);
    }

 运行的结果如下:

 



posted @ 2017-12-11 19:16  NeilZhang  阅读(217)  评论(0编辑  收藏  举报