设计模式学习_观察者模式

观察者模式 Observer Pattern

这是一种很好解释:气象监测总部WeatherStation与我们的手机APP PhoneDisplay之间的关系。

我们看天气的时候,数据都是依照最新的数据变化而变化的,而变化的数据,来源于具体发送数据的仪器(比如天气传感器 Weather Sensor)

也就是说,我们可以利用这种模式,来更好地在数据变化后,让所有显示器设备更新数据变化消息。

关键概念

1. 观察者模式定义了一种“一对多”的关系。

2. 当这个关系中的“一”,数据发生变化时,其中所依赖的“多”将会自动地进行变化。

在这里插入图片描述
解释:

  1. 这里ISubject与IObserver如何体现一对多关系?

  2. 为什么PhoneDisplay与TvDisplay要有WeatherStation呢?

对于第一个问题,我们在每个ISubject中,附上一个List<IObserver> observers列表。

对于第二个问题,回答是:我们的显示屏要显示数据变化,而这些数据来源始终是WeatherStation。

因此,update函数其实要用到WeatherStation的数据。

代码思路&实现:

  • 很简单,如果某一个时刻,WeatherStation中的数据(可以是成员变量)变化了,那么我们就执行notify()来通知List中的每一个Observer。

接下来,我们用代码来实现:

抽象接口层面:

  1. ISubject.java

    1
    2
    3
    4
    5
    6
    7
    8
    package com.company.inter;

    public interface ISubject {
    void add(IObserver iObserver);
    void remove(IObserver iObserver);
    void notifyObserver();
    }

  2. IObserver.java

    1
    2
    3
    4
    5
    package com.company.inter;

    public interface IObserver {
    void update();
    }

具体实现层面

  1. WeatherStation

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    package com.company.entity;

    import com.company.inter.IObserver;
    import com.company.inter.ISubject;

    import java.util.ArrayList;
    import java.util.List;

    public class WeatherStation implements ISubject {

    //被注册进来的所有观察者
    List<IObserver> observers = new ArrayList<>();

    //温度变量 当温度变量发生变化时 通知所有观察者
    Integer temperature = 18;

    //将观察者注册进来 其中就是用list add进来
    @Override
    public void add(IObserver iObserver) {
    this.observers.add(iObserver);
    }

    @Override
    public void remove(IObserver iObserver) {
    observers.remove(iObserver);
    }

    //在温度变量发生变化后 每一个观察者通过update方法来得到最新数据
    @Override
    public void notifyObserver() {
    //通知每一个观察者
    for(IObserver iObserver: this.observers){
    iObserver.update();
    }
    }

    public Integer getTemperature(){
    return this.temperature;
    }

    //模拟实现数据变化
    public void setTemperature(Integer temperature){
    this.temperature = temperature;
    }
    }
  2. PhoneDisplay.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.company.entity;

    import com.company.inter.IObserver;

    public class PhoneDisplay implements IObserver{

    WeatherStation weatherStation;

    //我们需要得到变化后的数据信息 因此需要通过构造方法 <绑定> 一个被观察者
    public PhoneDisplay(WeatherStation weatherStation){
    this.weatherStation = weatherStation;
    }

    //通过这个被观察者的public get方法 我们才可以知道最新的数据信息
    @Override
    public void update() {
    System.out.println("数据发生变化,最新温度为:" +
    this.weatherStation.getTemperature());
    }
    }
  3. TvDisplay.java

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    package com.company.entity;

    import com.company.inter.IObserver;

    public class TvDisplay implements IObserver{

    WeatherStation weatherStation;

    //我们需要得到变化后的数据信息 因此需要通过构造方法 <绑定> 一个被观察者
    public TvDisplay(WeatherStation weatherStation){
    this.weatherStation = weatherStation;
    }

    //通过这个被观察者的public get方法 我们才可以知道最新的数据信息
    @Override
    public void update() {
    System.out.println("数据发生变化,最新温度为:" +
    this.weatherStation.getTemperature());
    }
    }

主函数:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
package com.company;

import com.company.entity.PhoneDisplay;
import com.company.entity.TvDisplay;
import com.company.entity.WeatherStation;

public class Main {

public static void main(String[] args) {
WeatherStation weatherStation = new WeatherStation();

//手机显示器实时绑定天气预报站台
PhoneDisplay phoneDisplay = new PhoneDisplay(weatherStation);
//电视机显示器实时绑定天气预报站台
TvDisplay tvDisplay = new TvDisplay(weatherStation);

//天气预报站台将手机显示器注册进来
weatherStation.add(phoneDisplay);
//天气预报站台将电视机显示器注册进来
weatherStation.add(tvDisplay);

System.out.println("天气正常,一直都是:" +
String.valueOf(weatherStation.getTemperature()) + "摄氏度.");


System.out.println("某一时刻,数据突然发生变化...");
weatherStation.setTemperature(-20);

System.out.println("天气预报站台准备广播消息!Broadcasting...");

weatherStation.notifyObserver();

System.out.print("手机显示器这边显示:");
phoneDisplay.update();

System.out.print("电视机显示器这边显示:");
tvDisplay.update();
}
}

效果图

在这里插入图片描述