观察者模式--java实现

205 阅读2分钟

天气预报项目需求,具体要求如下:

  1. 气象站可以将每天测量到的温度、湿度、气压等以公告的形式发布出去(如:发布到自己的网站或第三方)。
  2. 需要设计开放型API,便于其他第三方也能接入气象站获取数据。
  3. 提供温度、湿度、气压的接口。
  4. 测量数据更新时,要能实时的显示或通知给第三方。 普通方案: 通过对气象站项目的分析,我们可以初步设计出一个WeatherData类和WeatherStation类,WeatherData类里面包含了具体的气象数据,当气象数据变更时去更新WeatherStation的公告板。

image.png

@Data
public class WeatherData {
    private float temperature;
    private float humidity;
    private float pressure;

    private WeatherStation weatherData;

    public WeatherData(WeatherStation weatherStation) {
        this.weatherData = weatherStation;
    }

    public void dataChange(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        weatherData.update(this);
    }
}
public class WeatherStation {
    public void update(WeatherData weatherData) {
        display(weatherData);
    }

    public void display(WeatherData weatherData) {
        System.out.println("气象局显示温度" + weatherData.getTemperature());
        System.out.println("气象局显示湿度" + weatherData.getHumidity());
        System.out.println("气象局显示气压" + weatherData.getPressure());
    }
}
public class WeatherTest {
    public static void main(String[] args) {
        WeatherStation weatherStation = new WeatherStation();
        WeatherData weatherData = new WeatherData(weatherStation);
        weatherData.dataChange(20f,20f,1f);
    }
}

问题分析: WeatherData类新接入一个第三方时,要加一个成员编码,dataChange方法需要调用第三方的update方法。

image.png

  1. 其他第三方接入气象站获取数据的问题-->扩展性不好。
  2. 无法在运行时动态的添加第三方。

使用观察者模式来解决

image.png

public interface Subject {
    void registerObserver(Observer object);

    void remove(Observer object);

    void notifyObservers();
}
@Data
public class WeatherData implements Subject {
    private float temperature;
    private float humidity;
    private float pressure;

    private List<Observer> observers = new ArrayList<>();

    @Override
    public void registerObserver(Observer observer) {
        if (!observers.contains(observer)) {
            observers.add(observer);
        }
    }

    @Override
    public void remove(Observer observer) {
        if (observers.contains(observer)) {
            observers.remove(observer);
        }
    }

    @Override
    public void notifyObservers() {
        System.out.println("===数据变更,通知观察者");
        observers.stream().forEach(o -> o.update(this));
    }

    public void dataChange(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }
}
public interface Observer {
    void update(Object object);
}
public class WeatherStation implements Observer {
    @Override
    public void update(Object object) {
        WeatherData weatherData = (WeatherData) object;
        System.out.println("气象局显示温度" + weatherData.getTemperature());
        System.out.println("气象局显示湿度" + weatherData.getHumidity());
        System.out.println("气象局显示气压" + weatherData.getPressure());
    }
}
public class WeatherTest {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        weatherData.registerObserver(new WeatherStation());
        weatherData.dataChange(1, 2, 3);

        SinaStation sinaStation = new SinaStation();
        weatherData.registerObserver(sinaStation);
        weatherData.dataChange(2, 3, 4);

        weatherData.registerObserver(new BaiduStation());
        weatherData.dataChange(3, 4, 5);

        weatherData.remove(sinaStation);
        weatherData.dataChange(4, 5, 6);
    }
}

观察者模式的好处

  1. 观察者模式设计后,会以集合的方式来管理用户(Observer),register、remove、notify
  2. 我们增加观察者时,就不需要改核心类WeatherData,遵守了ocp原则。 观察者模式在JDK应用的源码分析

JDK的Observable类就使用了观察者模式

  • java.util.Observable
  • java.util.Observer
  • Observable的作用和地位等价于Subject
  • Observable是类,不是接口,类中实现了核心的方法,即管理Observer的方法,add、delete、notify
  • Observer观察者,当信息变化时Observable会通知它。