设计模式之观察者模式


前言

大家好,我是练习两年半的Java练习生,最近阅读了《深入浅出设计模式(中文版)》,学习了各种设计模式,所以想出一个专栏和大家分享一下!
如果大家觉得文章还可以,欢迎关注点赞!后续还会陆续更新!!


一、定义

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

二、类图

实现观察者不止一种,但常见的是Subject 和 Observer

  1. 之间的依赖是什么?
    主题是真正拥有数据的人,观察者是主题的依赖者,在数据变化时更新。
    主题只知道 观察者 实现了某个接口(也就是Observer接口),主题不需要知道观察者的具体类是谁,做了什么
    因为主题唯一依赖的东西是一个实现了Observer接口的对象列表,所以我们随时可以增加观察者,不会对主题产生影响。

  2. 使用到的原则:为了交互对象之间的松耦合设计而努力。
    体现在改变主题或观察者其中的一方,并不会影响另一方,两者之间是松耦合的

三、应用

需求

此系统中的三个部分是气象站(获取实际气象数据的物理装置)、WeatherData对象(追踪来自气象站的数据,并更新布告板)和布告板(显示目前天气状况给用户看)。
image.png

分析

我们拿到这个weatherData ,可能会使用下面的方法进行

错误示范

public class WeatherData{
//实例变量声明
public void measurementsChanged(){
	float temp  = getTemperature();
    float humidity  = getHumidity();
    float pressure = getPressure();

    currentConditionDisplay.update(temp,humidity,pressure);
    statisticDisplay.update(temp,humidity,pressure);
    forecastDisplay.update(temp,humidity,pressure);
}
}

如果这么做的话,我们每次增加一个观察者的时候,就需要修改这个方法,违背了对修改关闭,对扩展开放原则。

实现

首先,我们定义一个主题(Subject)接口,该接口定义了添加观察者、删除观察者、通知观察者等方法:

public interface Subject {
    void registerObserver(Observer observer);
    void removeObserver(Observer observer);
    void notifyObservers();
}

接下来,我们定义一个具体主题(具体气象站)类 WeatherData,该类实现了主题接口,并存储了温度、湿度和气压的值,并提供了相应的getter和setter方法:

public class WeatherData implements Subject {
    private float temperature;
    private float humidity;
    private float pressure;
    private List<Observer> observers;

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

    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    public void removeObserver(Observer observer) {
        int index = observers.indexOf(observer);
        if (index >= 0) {
            observers.remove(index);
        }
    }

    public void notifyObservers() {
        for (Observer observer : observers) {
            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;
        measurementsChanged();
    }

    public float getTemperature() {
        return temperature;
    }

    public float getHumidity() {
        return humidity;
    }

    public float getPressure() {
        return pressure;
    }
}

接下来,我们定义一个观察者(Observer)接口,该接口定义了更新方法:

public interface Observer {
    void update(float temperature, float humidity, float pressure);
}

最后,我们定义一个具体观察者(具体手机App、具体电视机)类 CurrentConditionsDisplay,该类实现了观察者接口,并实现了更新方法,当气象数据发生变化时,该类会更新温度、湿度和气压的值:

public class CurrentConditionsDisplay implements Observer {
    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData;

    public CurrentConditionsDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData
		weatherData.registerObserver(this);
	}
    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("Current conditions: " + temperature
        + "F degrees and " + humidity + "% humidity and " + pressure + " pressure");
}
}

在这个示例中,我们创建了一个WeatherData对象作为主题,并创建了一个CurrentConditionsDisplay对象作为观察者。当WeatherData的气象数据发生变化时,它会自动通知所有观察者对象进行更新,例如CurrentConditionsDisplay对象会更新自己的温度、湿度和气压的值并进行显示。

可以看到,观察者模式能够帮助我们实现对象之间的松耦合,让对象之间的交互更加灵活和可扩展。在实际开发中,我们可以将观察者模式应用于各种场景,例如GUI编程中的事件处理、消息通知系统等。

使用Java的观察者模式

其实,观察者模式在消息处理上有两种方式,一种是主题推送模式,像我们的微信公众号一下,推送消息给关注该公众号的人。而另外一种是拉取模式,就是有需要才调用拉取主题的信息

在java.util包内包含最基本的Observer和Observable类,这个和Subject和Observer相似,甚至更方便一些,因为许多功能都已经准备好了。
什么时候是拉消息?什么时候是推消息呢?

我们来看看java中Observable中的notifyObservers()方法

image.png
可知,我们是用过changed来设置是推模式还是拉模式。默认情况下,java是拉模式,如果调用了setChanged()方法,就更改为推模式

public class GeneralDisplay implements Observer {

    private float temperature;
    private float humidity;
    private float pressure;

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("更新观察者数据");
        WeatherData data = (WeatherData) arg;
        temperature = data.getTemperature();
        humidity = data.getHumidity();
        pressure = data.getPressure();
        display();
    }

    public void display(){
        System.out.println("温度 : " + temperature + "湿度:" + humidity + "气压:" + pressure);
    }
}

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

    public void measurementsChanged(float temperature,float humidity,float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;

        setChanged();
        notifyObservers(this);
    }


    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 class Test {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        weatherData.setTemperature(12);
        weatherData.setHumidity(22);
        weatherData.setPressure(32);

        GeneralDisplay generalDisplay = new GeneralDisplay();
        weatherData.addObserver(generalDisplay);


        weatherData.measurementsChanged(11,22,33);

        weatherData.measurementsChanged(1,2,3);

    }
}

四、问题

如何添加一个新的观察者?需要做哪些事情?


五、总结

以上就是今天要讲的内容,本文介绍了设计模式中的观察者模式,这个模式是实现对象之间的一对多依赖,订阅主题、主题推送是我们这节的核心内容。我们要记住一个原则,为了交互对象之间的松耦合设计而努力。
同时,在Java中提供的观察者也需要了解一下,明白什么是推模式、什么是拉模式。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值