觀察者模式的理解和使用


一、是什么?作用

1. 觀察者模式定義了一系列對象之間的一對多關系

2. 當一個對象改變狀態, 其他依賴着都會受到通知

二、示例

需求: 氣象觀測天氣,並定時更新觀測數據,我們的電子儀器需要接受這些數據

1. PUSH模式, 由被觀察者推送給觀察者

1. 定義主題, 即被觀察者

/**
 * 主題
 */
public interface Subject {

    // 添加觀察者
    void registerObserver(Observer o);

    // 刪除觀察者
    void removeObserver(Observer o);

    // 通知
    void notifyObservers();
}

2. 定義觀察者的超類,里面只有一個更新的方法

/**
 * 觀察者超類
 */
public interface Observer {

    public void update(float temp, float humidity, float pressure);
}

3. 天氣數據, 主題的子類

  1. 有一個屬性來存放觀察者

  2. 實現主題的方法

  3. 有三個數據需要傳遞(溫度、濕度、氣壓)

 1 /**
 2  * 天氣數據, 實現主題
 3  */
 4 public class WeatherData implements Subject {
 5 
 6     /**
 7      * 存儲觀察者
 8      */
 9     private List<Observer> observers;
10     private float temperature;
11     private float humidity;
12     private float pressure;
13 
14     public WeatherData() {
15         this.observers = new ArrayList<>();
16     }
17 
18     /**
19      * 當氣象站得到更新觀測值時,我們通知觀察者
20      */
21     public void measurementsChanged() {
22         notifyObservers();
23     }
24 
25     /**
26      * 模擬氣象站更改了氣象數據
27      */
28     public void setMeasurements(float temperature, float humidity, float pressure) {
29         // 更改氣象數據
30         this.temperature = temperature;
31         this.humidity = humidity;
32         this.pressure = pressure;
33 
34         // 通知觀察者
35         measurementsChanged();
36     }
37 
38     @Override
39     public void registerObserver(Observer o) {
40         observers.add(o);
41     }
42 
43     @Override
44     public void removeObserver(Observer o) {
45         int i = observers.indexOf(0);
46         if (i >= 0) {
47             observers.remove(0);
48         }
49     }
50 
51     @Override
52     public void notifyObservers() {
53         for (Observer observer : observers) {
54             observer.update(temperature, humidity, pressure);
55         }
56     }
57 
58     public float getTemperature() {
59         return temperature;
60     }
61 
62     public float getHumidity() {
63         return humidity;
64     }
65 
66     public float getPressure() {
67         return pressure;
68     }
69 }

4. 觀察者具體類, 實現觀察者,將主題通過構造傳入,並訂閱(這里將耦合度降到了很低了),實現更新方法

/**
 * 顯示當前天氣的儀器 - 觀察者的具體類
 */
public class NowConditionDisplay implements Observer {
    private float temperature;
    private float humidity;
    private WeatherData weatherData;

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

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

    public void display() {
        System.out.println("[push] 當前溫度:" + temperature + " 當前濕度: " + humidity);
    }
}

測試

public class pushMain {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        NowConditionDisplay nowConditionDisplay = new NowConditionDisplay(weatherData);

        weatherData.setMeasurements(20, 10, 29.2f);
    }
}


控制台顯示:
[push] 當前溫度:20.0 當前濕度: 10.0

2. PULL模式, 由觀察者去拉數據

1. 天氣數據提供者,利用java.util包下的Observable類來實現

import java.util.Observable;

/**
 * 數據提供者
 */
public class WeatherData extends Observable {

    // 三個數據
    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;
    }
}

2. 觀察者子類, 實現java.util的Observer 

import java.util.Observable;
import java.util.Observer;

/**
 * @author wb-xp570304 on 2019/7/9
 */
public class NowConditionDisplay implements Observer {

    Observable observable;
    private float temperature;
    private float humidity;

    public NowConditionDisplay(Observable observable) {
        this.observable = observable;
        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();
            display();
        }
    }

    public void display() {
        System.out.println("當前溫度: " + temperature + " 濕度: " + humidity);
    }
}

測試:

public class pullMain {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();

        NowConditionDisplay nowConditionDisplay = new NowConditionDisplay(weatherData);

        weatherData.setMeasurements(80, 65, 30f);
    }
}

控制台顯示:
  當前溫度: 80.0 濕度: 65.0

小結: 

  第二種pull的方式這里是利用java.util.Observable來實現的,而且用的是繼承,減少了代碼的可擴展性

三、總結

 1. 觀察者模式的理念是,為交互對象之間的松耦合設計而努力


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM