观察者(Observer)模式

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

通俗来说:举个报社(主题)和订阅报纸的家庭(观察者)例子。

  • 报社的业务就是出版报纸。

  • 向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。

  • 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。

  • 只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或取消订阅报纸。

 

2、实现观察者模式

   (1)包含Subject接口和Observer接口

   (2)Java内置的观察者模式,在java.util包下包含最基本的Observer接口与Observable类。

3、包含Subject接口和Observer接口的代码实现

       业务场景:系统中的三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对 象(追踪来自气象站的数据,并   更新布告板)和布告板(显示目前天气状况给用 户看)。 我们的工作就是建立一个应用,利用WeatherData对象取得数据,并 更新布告板:实时显示目前天气状况。

      3.1、新建一个Sbuject主题接口

public interface Subject {
    // 注册观察者
    public void registerObserver(Observer o);
    // 删除观察者
    public void removeObserver(Observer o);
    // 当主题状态改变时,通知所有观察者
    public void notifyObservers();
}

    3.2   新建Observer观察者接口

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

3.3   新建DisplayElement   ,布告版显示接口 

public interface DisplayElement {
    /*
    DisplayElement接口只包含了一个方法, 也就是display()。当布告板需要显示时, 调用此方法。
    */
    public void display();
}

3.4 创建具体的Subject类,实现Subject接口

public class WeatherData implements Subject {
    private ArrayList observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList();
    }
    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }
    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i > 0) {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObservers() {
        for(int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer) observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }

    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

   3.5  创建具体的布告板(Observer)类,实现Observer接口和display接口,可更新布告板信息。

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData;

    public  CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }
    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature + " degrees and " + humidity + "% humidity and "
                + pressure + "% pressure" );
    }

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

 3.6  最后,建立气象站类,当天气情况改变时候,看看输出结果。

/**
 * @ClassName WeatherStation
 * @Description 更新天气公告板
 * @Author 
 * @Date 2018/11/7 14:51
 */
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(50, 75, 43.4f);
    }
}

 输出结果:

Current conditions: 80.0 degrees and 65.0% humidity and 30.4% pressure
Current conditions: 50.0 degrees and 75.0% humidity and 43.4% pressure

4、要点:

  • 观察者模式定义了对象之间一对多的关系。 

  • 主题(也就是可观察者)用一 个共同的接口来更新观察者 。

  •  观察者和可观察者(主题)之间用松耦合方式结合(loosecoupling),可观察者不知道观察者的细节,只知道观察者实现 了观察者接口。 

  • 使用此模式时,你可从被观察 者处推(push)或拉(pull) 数据(然而,推的方式被认为 更“正确”)。 

  •  有多个观察者时,不可以依赖特定的通知次序。 

  • Java有多种观察者模式的实 现,包括了通用的java.util. Observable。 

  • 要注意java.util.Observable(是一个类实现上所带来的一些问题)。 

  • 如果有必要的话,可以实现自 己的Observable,这并不难,不要害怕。 

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

  • 观察者模式也被应用在许多地方, 例如:JavaBeans、RMI。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章