设计模式-2-观察者模式

162 阅读2分钟

今天的需求是要实现一个天气预报系统,当然天气预报的数据不需要我们自己去观测和记录,已经有气象局完成了这个工作, 并且提供给我们一个类:

public class WeatherData {

    private float getPressure() {
        return 0;
    }

    private float getHumidity() {
        return 0;
    }

    private float getTemperature() {
        return 1;
    }

    public void measurementsChanged() {
        //TODO 获得通知后,实现相应的内容
    }
}

这个类中有提供,温度、湿度、气压的获取手段,并且当气象局采集到数据后,会调用measurementsChanged,这里我们不关心是怎么被调用到的,只要知道,当数据采集回来后,measurementsChanged方法会被调用。如果是你的话,你会怎么实现?

如果是我,我会在measurementsChanged方法里实现我的逻辑。

public class WeatherData {

    private float getPressure() {
        return 0;
    }

    private float getHumidity() {
        return 0;
    }

    private float getTemperature() {
        return 1;
    }

    public void measurementsChanged() {
        currentConditionsDisplay.update(getHumidity(), getTemperature(), getPressure());
      	forcastDisplay.update(getHumidity(), getTemperature(), getPressure());
      	statisticDisplay.update(getHumidity(), getTemperature(), getPressure());
    }
}

可是这样实现的问题在于,如果有更多的公司接入天气预报系统,measurementsChanged方法就要极度膨胀,一直不断的被改写。根据设计模式的原则:针对接口编程 和 把变化的部分剥离出来,我们需要对measurementsChanged方法进行整改,使其适合作为公共API对外提供服务。

那么我们来分析一下我们的需求:

  1. 我们需要在气象局获得数据的时候通知到我们
  2. 能够灵活动态的增加和删除被通知对象,不必每次增加或删除被通知者时都要改写WeatherData代码。

结合第一版的实现逻辑,我们很容易的能想到,可以设计一个更新动作的接口,所有实现类都实现这个接口那么,我们就可以把measurementsChanged方法简化成一行。

public class WeatherData {

    public Observer observer;

    public void measurementsChanged() {
        observer.update(getHumidity(), getTemperature(), getPressure());
    }
}

其次,我们要能够动态的增加和删除被通知者,所以我们需要持有(has a)通知对象,在需要通知的时候遍历就可以了。我们还要增加添加和删除被通知者的方法,用来动态的管理被通知对象。

public class WeatherData {

    public List<Observer> observers = new ArrayList<>();
    public void addObserver(Observer observer) {
        observers.add(observer);
    }
    public void delObserver(Observer observer) {
        observers.remove(observer);
    }
    public void notifierObservers() {
        for(Observer o:observers) {
            o.update(getHumidity(), getTemperature(), getPressure());
        }
    }
    public void measurementsChanged() {
        notifierObservers();
    }
}

作为被观察者,我们需要持有WeatherData对象,才能把”自己“添加到WeatherData或者从WeatherData删除。

public class ForcastObserver implements Observer {
    public float temperature;
    public float humidity;
    public float pressure;

    public WeatherData weatherData;

    public ForcastObserver (WeatherData weatherData) {
        this.weatherData = weatherData;
        weatherData.addObserver(this);
    }

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

    public void display() {
        System.out.println(temperature + humidity + pressure);
    }
}

测试代码如下:

public class TestForcastObserver {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        ForcastObserver forcastObserver = new ForcastObserver(weatherData);
        weatherData.measurementsChanged();
    }
}