设计模式-观察者模式

气象站建立

需求:

  1. 气象站必须建立在WeatherData对象上。
  2. 三种布告板,显示目前的气象统计以及简单的预报。
  3. WeatherData对象获得最新的测量数据时,三种布告板必须实时更新。
  4. 可扩展。

气象监测应用概况

此系统中的三个部分是:

  1. 气象站(获取实际气象数据的物理装置)。
  2. WeatherData对象(追踪来自气象站的数据,并更新布告板)。
  3. 布告板(显示目前天气状况给用户看)。

WeatherData对象知道如何跟物理气象站联系,以取得更新的数据。WeatherData对象会随即更新三个布告板的显示:目前状况(温度、湿度、气压)、气象统计和天气预报。

image

目前已知信息如下:

  1. WeatherData类具有getter方法,可以取得三个测量值:温度、湿度与气压。
  2. 当新的测量数据备妥时,measurementsChanged()方法就会被调用(我们不在乎此方法是如何被调用的,我们只在乎它被调用了)。
  3. 我们需要实现三个使用天气数据的布告板:“目前状况”布告、“气象统计”布告、“天气预报”布告。一旦WeatherData有新的测量,这些布告必须马上更新。
  4. 此系统必须可扩展,其他开发人员可定制布告板。

错误的示范

在measurementsChanged()方法中添加我们的代码:

public class WeatherData{
    public void measurementsChanged(){
        float temp = getTemperature();
        float humidity = getHumidity();
        float pressure = getPressure();
        
        //调用每个布告板更新显示,传入最新的测量
        currentConditionsDisplay.update(temp,humidity,pressure);
        statisticsDisplay.update(temp,humidity,pressure);
        forecastDisplay.update(temp,humidity,pressure);
    }
}

我们的实现有什么不对?

  1. 针对具体实现编程,会导致我们以后在增加或删除布告板时必须修改程序。
  2. 改变的地方,需要封装起来。
  3. update方法参数相同,这里更像是一个统一的接口。

认识观察者模式

我们先来看看报纸和杂志的订阅是怎么回事:

  1. 报社的业务就是出版报纸。
  2. 向某家报社订阅报纸,只要它们有新报纸出版,就会给你送来,只要你是他们的订户,你就会一直收到新报纸。
  3. 当你不想再看报纸的时候,取消订阅,他们呢就不会再送新报纸来。
  4. 只要报社还在运营,就会一直有人(或单位)向它们订阅报纸或取消订阅报纸。

出版者+订阅者=观察者模式

  1. 主题对象管理某些数据。
  2. 当主题内的数据改变,就会通知观察者。
  3. 一旦数据改变,新的数据会以某种形式送到观察者手上。
  4. 观察者已经订阅(注册)主题以便在主题数据改变时能够收到更新。
  5. 不是观察者的对象,不会被通知。

定义观察者模式

观察者模式定义了对象之间的一对多依赖,这样以来,当一个对象改变状态时,它的所有依赖者都会收到通知并自动更新。

  • 观察者模式定义了一系列对象之间的一对多关系。
  • 当一个对象改变状态时,其他依赖者都会收到通知。

image

当两个对象之间松耦合,它们依然可以交互,但是不太清楚彼此的细节。

观察者模式提供了一种对象设计,让主题和观察者之间松耦合。

我们可以独立地复用主题或观察者。如果我们在其他地方需要使用主题或观察者,可以轻易地复用,因为二者并非紧耦合。

设计气象站

image

实现气象站

/**
 * 主题抽象
 * Created on 2022/9/17
 *
 * @author: jia_xx
 */
public interface Subject {
    /**
     * 观察者注册
     *
     * @param o
     */
    void registerObserver(Observer o);

    /**
     * 观察者删除
     *
     * @param o
     */
    void removeObserver(Observer o);

    /**
     * 当主题状态改变时,这个方法会被调用,以通知所有的观察者
     */
    void notifyObservers();
}
/**
 * 观察者抽象
 * Created on 2022/9/17
 *
 * @author: jia_xx
 */
public interface Observer {
    /**
     * 当气象观测值改变时,主题会把这些状态值当作方法的参数,传送给观察者。
     *
     * @param temp
     * @param humidity
     * @param pressure
     */
    void update(float temp, float humidity, float pressure);
}

/**
 * 布告板显示接口
 * Created on 2022/9/17
 *
 * @author: jia_xx
 */
public interface DisplayElement {
    /**
     * 当布告板需要显示时,调用此方法
     */
    void display();
}
/**
 * 主题实现
 * @ClassName WeatherData
 * @Author jia_xx
 * @Date 2022/9/17 23:18
 */
public class WeatherData implements Subject {
    private List<Observer> observers;
    private float temperature;
    private float humidity;
    private float pressure;

    public WeatherData() {
        observers = new ArrayList();
    }

    @Override
    public void registerObserver(Observer o) {
        observers.add(o);
    }

    @Override
    public void removeObserver(Observer o) {
        int i = observers.indexOf(o);
        if (i >= 0) {
            observers.remove(i);
        }
    }

    @Override
    public void notifyObservers() {
        for (int i = 0; i < observers.size(); i++) {
            Observer observer = (Observer) observers.get(i);
            observer.update(temperature, humidity, pressure);
        }
    }

    public void measurementsChanged() {
        notifyObservers();
    }


    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
    }
}
/**
 * 布告板实现
 * @ClassName CurrentConditionsDisplay
 * @Author jia_xx
 * @Date 2022/9/17 23:19
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

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

    @Override
    public void display() {
        System.out.println("current conditions: " + temperature + "F degrees and " + humidity + "% humidity");
    }
    
}
/**
 * 观察者模式测试类(气象站实现)
 * @ClassName WeatherStation
 * @Author jia_xx
 * @Date 2022/9/17 23:26
 */
public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.setMeasurements(80,65,30.4f);
        weatherData.measurementsChanged();
    }
}

output:
current conditions: 80.0F degrees and 65.0% humidity

使用java内置的观察者模式

/**
 * @ClassName WeatherData
 * @Author jia_xx
 * @Date 2022/9/21 22:28
 */
public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    /**
     * 构造器不再需要为了记住观察者们而建立数据结构了
     */
    public WeatherData(){}

    public void measurementsChanged(float temperature, float humidity, float pressure){
        //在拉取之前,状态改变
//        setChanged();
        //notifyObservers没有传送数据对象,这表示我们采用的做法是“拉”
//        notifyObservers();
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
    }

    /**
     * 观察者利用这些方法取得WeatherData对象的状态
     * @return
     */
    public float getTemperature(){
        return temperature;
    }
    public float getHumidity(){
        return humidity;
    }
    public float getPressure(){
        return pressure;
    }
}
/**
 * @ClassName CurrentConditionsDisplay
 * @Author jia_xx
 * @Date 2022/9/21 22:51
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    //主题对象
    Observable observable;
    private float temperature;
    private float humidity;

    public CurrentConditionsDisplay(Observable observable){
        this.observable = observable;
        observable.addObserver(this);
    }
    @Override
    public void display() {
        System.out.println("current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
    }

    @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();
        }
    }
}
/**
 * @ClassName Test
 * @Author jia_xx
 * @Date 2022/9/21 22:45
 */
public class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        weatherData.measurementsChanged(80,65,30.4f);
        currentConditionsDisplay.update(weatherData,null);
    }
}
  • Observable是一个类,非接口,限制了Observable的复用潜力。
  • Observable将关键方法保护起来,setChange()被定义成protected。
  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值