01.观察者模式

01.观察者模式

1、认识观察者模式:

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

(1)报社的业务就是出版报纸。

(2)向某家报社订阅报纸,只要他们有新报纸出版,就会给你送来。只要你是他们的订户,你就会一直收到新报纸。

(3) 当你不想再看报纸的时候,取消订阅,他们就不会再送新报纸来。

(4)只要报社还在运营,就会一直有人(或单位)向他们订阅报纸或者取消订阅报纸。

2、定义:

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

主题和观察者定义了一对多的关系。观察者依赖于此主题,只要主题状态一有变化,观察者就会被通知。根据通知的风格,观察者可能因此新值而更新。

实现观察者模式的方法不止一种,包含 Subject 和 Observer 接口的类最为常见。

C8CE0C4C-F581-445E-B2F4-_1_105_c

3、设计原则:

为了交互对象之间的松耦合设计而努力。

松耦合的设计之所以能让我们建立有弹性的OO系统,能够应对变化,是因为对象之间的互相依赖降到最低。

因为任何时候我们都可以添加新的观察者,因为主题唯一依赖的东西是一个实现Observer接口的对象列表。

4、举例(气象站项目):

4.1 需求:

(1)该气象站必须建立在专利申请的 WeatherData 对象上,由 WeatherData 对象负责追踪目前的天气状况(温度、湿度、气压)。

(2)建立一个应用,有三种布告板(后面可能会有更多),分别显示目前的状态、气象统计和简单的预报(三种不同形式的展示)。当WeatherData 改变时,三种布告板必须实时更新。

4.2 设计:

008068C1-4A49-44AE-A02FFFCBDB_1_201_a

4.3 代码实现:

(1)观察者接口

/**
 * 观察者接口
 *
 * 所有观察者都要实现此接口
 */
public interface Observer {
    /**
     * 当气象观察值改变时,主题会把这些状态值传给观察者
     * @param temp
     * @param humidity
     * @param pressure
     */
    public void update(float temp, float humidity, float pressure);
}

(2)主题接口

/**
 * 主题接口
 *
 * 所有主题都要实现此接口
 */
public interface Subject {
    /**
     * 观察者注册接口
     * @param o
     */
    public void registerObserver(Observer o);

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

    /**
     * 当主题状态改变时,通过这个方法告知所有的观察者
     */
    public void notifyObservers();

}

(3)布告板接口

/**
 * 布告板接口
 *
 * 所有布告板要实现此接口
 */
public interface DisplatElement {
    /**
     * 当布告板需要显示时,调用此方法
     */
    public void display();
}

(4)主题实现类 - 天气数据

/**
 * 天气数据
 * 
 * 主题实现类
 */
public class WeatherData implements Subject {
    /**
     * 记录所有观察者
     */
    private ArrayList observers;
    /**
     * 温度
     */
    private float temperature;
    /**
     * 湿度
     */
    private float humidity;
    /**
     * 气压
     */
    private float pressure;

    public WeatherData(ArrayList observers) {
        this.observers = observers;
    }

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

    @Override
    public void removeObserver(Observer o) {
        observers.remove(o);
    }

    @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(){
        //TODO 检测是否达到通知条件,比如必须是温度等条件达到0.5的浮动再通知观察者

        notifyObservers();
    }

    /**
     * 当传感器返回测量的数据,会调用此方法
     * @param temperature
     * @param humidity
     * @param pressure
     */
    public void setMeasurements(float temperature,float humidity,float pressure){
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }

}

(5)三个布告板实现类,只有现实的属性不同。

public class CurrentConditionsDisplay implements Observer, DisplatElement {
    /**
     * 温度
     */
    private float temperature;
    /**
     * 湿度
     */
    private float humidity;

    /**
     * 主题
     */
    private Subject weatherData;

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

    @Override
    public void display() {
        System.out.println("CurrentConditionsDisplay【temperature:" +  temperature + ";humidity:" + humidity+"】");
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        display();
    }
}
public class ForecastDisplay implements Observer, DisplatElement {
    /**
     * 湿度
     */
    private float humidity;
    /**
     * 气压
     */
    private float pressure;

    /**
     * 主题
     */
    private Subject weatherData;

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

    @Override
    public void display() {
        System.out.println("ForecastDisplay【humidity:" +  humidity + ";pressure:" + pressure+"】");
    }

    @Override
    public void update(float temp, float humidity, float pressure) {
        this.pressure = pressure;
        this.humidity = humidity;
        display();
    }
}
public class StatisticsDisplay implements Observer, DisplatElement {
    /**
     * 温度
     */
    private float temperature;

    /**
     * 气压
     */
    private float pressure;

    /**
     * 主题
     */
    private Subject weatherData;

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

    @Override
    public void display() {
        System.out.println("StatisticsDisplay【temperature:" +  temperature + ";pressure:" + pressure+"】");
    }

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

(6)测试类

public class WeatherStation {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData(new ArrayList<Observer>());

        CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
        StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData);

        weatherData.setMeasurements(50,60,30f);
        weatherData.setMeasurements(40,50,20f);
        weatherData.setMeasurements(60,20,40f);
    }
}

0308F50D-DD12-4D3C-8FD3-BBFCFD9A7962_1_201_a

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值