【设计模式】观察者模式

一、简介

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

有很多项目都用到了该设计模式,比如Spring的事件机制、消息队列等。
Java提供了两个接口java.util.Observablejava.util.Observer,也可以利用这两个接口实现。

类图如下:

 

观察者模式类图
观察者模式类图

 

二、示例

需求背景是气象站发布天气数据,所有订阅了气象站的布告板显示天气数据。
先上类图:

 

enter description here
enter description here

主题接口

 

/**
 * 主题接口
 * Created by 2YSP on 2018/1/24.
 */
public interface Subject {
    /**
     * 注册一个观察者
     * @param observer
     */
     void registerObserver(Observer observer);

    /**
     * 移除一个观察者
     * @param observer
     */
     void removeObserver(Observer observer);

    /**
     * 通知所有观察者
     */
     void notifyObservers();
}

观察者接口

public interface Observer {
    /**
     * 所有观察者必须实现该方法,
     * 当气象观测值改变时,主题会把这些状态值当参数传给观察者
     * @param temp
     * @param humidity
     * @param pressure
     */
     void update(float temp,float humidity,float pressure);
}

具体主题WeatherData

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 observer) {
        observers.add(observer);
    }

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

    @Override
    public void notifyObservers() {
        observers.forEach(o -> {
            o.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;
        measurementsChanged();
    }

    //WeatherData的其他方法
}

当前状况布告板,这里只弄了一个,还可以根据自己的需求定义其他种类的布告板。

/**
 * 当前状况布告板(还可以建立其他观察者)
 * Created by 2YSP on 2018/1/24.
 */
public class CurrentConditionDisplay implements Observer,DisplayElement {
    /**
     * 温度
     */
    private float temperature;
    /**
     * 湿度
     */
    private float humidity;

    private Subject weatherData;

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

    @Override
    public void display() {
        System.out.println("Current conditions: "+temperature+"F degrees and "+humidity+"% humidity");
    }

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

DisplayElement

public interface DisplayElement {
    /**
     * 布告板显示气象数据
     */
    void display();
}

气象站

public class WeatherStation {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionDisplay currentCondition = new CurrentConditionDisplay(weatherData);

        weatherData.setMeasurements(80,65,30.4f);
    }
}

运行main方法控制台输出如下,说明布告板收到了消息并自动更新。

Current conditions: 80.0F degrees and 65.0% humidity

注意: 这里是通过构造方法传入具体主题,然后调用具体主题的registerObserver(Observer observer) 方法来实现注册观察者的。在实际项目中,我们可以通过在spring的xml配置文件上配置进行观察者的注册,这样更加灵活,不用修改代码。需要给WeatherData添加一个setObservers(List observers) 方法,利用set方法注入。

        <bean id="weatherData" class="xx.xx.WeatherData">
            <property name="observers">
                <list>
                    <ref bean="currentConditionDisplay"/>
                </list>
            </property>
        </bean>
原文地址:https://www.cnblogs.com/2YSP/p/11602078.html