Java设计模式之观察者模式 - Go语言中文社区

Java设计模式之观察者模式


代码应该如同晚霞中的莲花一样地关闭(免于改变),如同晨曦中的莲花一
样地开放(能够扩展)

定义

观察者模式(Observer),又叫发布-订阅模式(Publish/Subscribe),定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并自动更新,大致构成如下

在这里插入图片描述

总结:
在这里插入图片描述

应用场景

现在又如下需求:
天气气象局可以测量天气的温度、湿度和气压,当需要测量新的天气测量数据measurementsChanged() 方法就会被调用,现在有2个需要使用天气数据的通知板,如果天气数据有更新,需要马上通知这两个通知板,并且未来可能会有其他通知板加入进来

这时候你需要如何设计? 这就是典型的发布订阅场景,只需要通知板订阅天气气象局即可,如果某个通知板不想受到气象通知了,取消订阅即可

代码实现

首先定义个 Subject 接口,接口中有一些对观察者的一些操作具体看代码注释
Subject

/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 22:12
 * @Description  主题接口
 */
public interface Subject {
    /**
     * 注册观察者
     * @param o
     */
    void registerObserver(Observer o);

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

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

}

WeatherData类,Subject 的具体实现
WeatherData

/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 22:23
 * @Description TODO
 */
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) {
        System.out.println("添加观察者");
        observers.add(o);
    }

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

    }


    @Override
    public void notifyObservers() {
        observers.forEach(s -> s.update(temperature, humidity, pressure));
    }
    /**
     * 通知给观察者
     */
    public void measurementsChanged() {
        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();
    }
}

这里再定义一个观察者接口Observer,用于观察者订阅消息的实现,即消息有update需要调用的方法
Observer

/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 22:14
 * @Description 观察者接口
 */
public interface Observer {
    /**
     * 抽象观察者具体实现
     * @param temp
     * @param humidity
     * @param pressure
     */
    void update(float temperature, float humidity, float pressure);
}

为了统一控制通知板的通知消息,我们抽象出一个DisplayElement接口出来控制订阅办的打印消息
DisplayElement

/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 22:21
 * @Description TODO
 */
public interface DisplayElement {

    /**
     * 布告板需要显示调用次方法
     */
    void display();
}

ForecastDisplay
现在是创建具体的观察者,观察者都应该实现Observer和DisplayElement接口

/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 23:07
 * @Description TODO
 */
public class ForecastDisplay implements Observer, DisplayElement {
    private float temperature;
    private float pressure;
    private Subject weatherData;


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

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

    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.pressure = pressure;
        display();
    }
}
/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 22:49
 * @Description 目前天气布告板
 */
public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Subject weatherData;

    /**
     * 注册为观察者
     * @param weatherData
     */
    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
    }

    /**
     * 显示最近温度湿度
     */
    @Override
    public void display() {
        System.out.println("Current conditions: " + temperature
                + "F degrees and " + humidity + "% humidity");
    }

    /**
     * 当调用update,将温度和湿度保存下来
     * @param temperature
     * @param humidity
     * @param pressure
     */
    @Override
    public void update(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        display();
    }
}

测试

/**
 * @author WH
 * @version 1.0
 * @date 2020/3/23 22:54
 * @Description TODO
 */
public class Test {

    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionsDisplay current = new CurrentConditionsDisplay(weatherData);
        ForecastDisplay forecastDisplay = new ForecastDisplay(weatherData);
        weatherData.setMeasurements(80, 65, 30.4f);
        weatherData.setMeasurements(82, 70, 29.2f);
        weatherData.setMeasurements(78, 90, 29.2f);

    }
}

在这里插入图片描述

如果我们需要添加新的通告版,只需要实现这两个接口,就可以自动通知了,如果我们其中有通告版不想受到消息了,移除自己即可,这就是观察者模式

Java内置的观察者模式

Java内置API支持实现观察者模式,其中观察者只需要实现内置的类Observer,之前的WeatherData也主需要继承内置Observable,用到了继承就知道以后的扩展肯定不会太好
大致改动如下
WeatherData

public class WeatherData extends Observable {
    private float temperature;
    private float humidity;
    private float pressure;

    public float getTemperature() {
        return temperature;
    }

    public void setTemperature(float temperature) {
        this.temperature = temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public void setHumidity(float humidity) {
        this.humidity = humidity;
    }

    public float getPressure() {
        return pressure;
    }

    public void setPressure(float pressure) {
        this.pressure = pressure;
    }

    /**
    * 不需要手动维护观察者
    * */
    public WeatherData() {
    }
    public void measurementsChanged() {
        setChanged();
        // 推送消息
        notifyObservers();
    }
    public void setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        measurementsChanged();
    }
}

CurrentConditionsDisplay

public class CurrentConditionsDisplay implements Observer, DisplayElement {
    private float temperature;
    private float humidity;
    private Observable observable;

    /**
     * 登记为观察者
     * @param observable
     */
    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();
        }
    }
}

版权声明:本文来源CSDN,感谢博主原创文章,遵循 CC 4.0 by-sa 版权协议,转载请附上原文出处链接和本声明。
原文链接:https://blog.csdn.net/qq_42651904/article/details/105208804
站方申明:本站部分内容来自社区用户分享,若涉及侵权,请联系站方删除。

0 条评论

请先 登录 后评论

官方社群

GO教程

猜你喜欢