观察者模式的理解和使用

一、是什么?作用

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. 观察者模式的理念是,为交互对象之间的松耦合设计而努力

posted @ 2019-07-17 10:30  Other+  阅读(4167)  评论(3编辑  收藏  举报