设计模式-观察者模式

观察者模式

简单描述:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。例如:up主和订阅者之间的关系,当up主有视频更新时,就会将更新通知给订阅者。

所属类型:行为型模式

适用情况:目标对象状态发生改变,所有观察者对象都得到通知,进行广播通知。

关键代码:需要一个列表用来存储观察者们

除了上述所说的up主和订阅者之间的关系之外,还可以通过气候信息改变情况举个栗子。每当气候发生改变的时候,气象站就会收到通知,并且将通知的结果通知给每一个关注气象站公众号的用户,所以下面用代码来实现这个例子。

首先需要创建气象站这个管理信息的功能,在这里创建一个Subject接口类型。

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

气象站能够对用户也就是所谓的观察者进行注册,移除以及通知用户的操作,所以定义了相关的方法。

接着就来创建Observer类,也就是所谓的观察者们

package observer;
​
public interface Observer {
    public void update(float temp, float humidity, float pressure);
}

顾名思义,观察者们的功能就只有接收对应的消息并且更新,所以仅定义updata一个方法就够了。

接着,通过创建一个DisplayElement接口来将对应的更新结果展示出来。

package observer;
​
public interface DisplayElement {
    public void display();
}

接口定义完成,接下来的具体的实现了。首先是对应的天气的数据,这里定义一个WeatherData类用来存储天气的信息,并且实现对应的注册观察者,移除观察者以及通知观察者的功能。

复制代码
package observer;
​
import java.util.ArrayList;
​
public class WeatherData implements Subject {
​
    private ArrayList 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 setMeasurements(float temperature, float humidity, float pressure) {
        this.temperature = temperature;
        this.humidity = humidity;
        this.pressure = pressure;
        notifyObservers();
    }
}
复制代码

在这个WeatherData类中,首先它的实例化需要新建一个列表用来存储观察者们,好在后面对这些观察者进行消息的通知。每当注册一个观察者registerObserver,就将观察者添加到这个观察者的列表当中。移除观察者removeObserver时就从这个列表中移除对应的观察者,在后面有数据更新的时候就不需要对已经移除的观察者进行通知。还有一个就是通知观察者的实现,在这个方法中,主要就是对列表中存在的观察者进行通知,调用每一个观察者的updata方法来更新个人的数据。

紧接着就来完成数据的展示功能,这里创建一个CurrentConditionDisplay类来将对应的数据展示出来,方便查看。

复制代码
package observer;
​
public class CurrentConditionDisplay implements Observer, DisplayElement {
​
    private float temperature;
    private float humidity;
    private float pressure;
    private Subject weatherData;
​
    public CurrentConditionDisplay(Subject weatherData) {
        this.weatherData = weatherData;
        weatherData.registerObserver(this);
​
    }
​
    @Override
    public void display() {
        System.out.println("temp: " + temperature + "\nhumidity: " + humidity + "\npressure: " + pressure);
    }
​
    @Override
    public void update(float temp, float humidity, float pressure) {
        this.temperature = temp;
        this.humidity = humidity;
        this.pressure = pressure;
        display();
    }
}
复制代码

首先需要创建温度,湿度以及压强三个属性来存储获取到的天气信息。这个气候展示的功能首先需要实现Observer接口的updata方法,来将数据传入并且调用DisplayElement接口的display方法来进行展示。

最后通过创建一个WeatherState类来进行调用查看结果。

复制代码
package observer;
​
public class WeatherState {
    public static void main(String[] args) {
        WeatherData weatherData = new WeatherData();
        CurrentConditionDisplay currentConditionDisplay =
                new CurrentConditionDisplay(weatherData);
        weatherData.setMeasurements(11, 11, 11);
        weatherData.setMeasurements(22, 22, 22);
        weatherData.setMeasurements(33, 33, 33);
    }
}
复制代码

运行结果如下所示:

复制代码
temp: 11.0
humidity: 11.0
pressure: 11.0
temp: 22.0
humidity: 22.0
pressure: 22.0
temp: 33.0
humidity: 33.0
pressure: 33.0
复制代码

发现每当调用一次setMeasurements方法就会将对应的数据进行输出。

同样,在Java中有内置的观察者模式,也就是ObserverObservable这两个类。对照着刚才的例子,可以将ObserverObserver进行对照,其中的方法也就只有一个updata类,Observable可以和Subject进行对照,两者的差距不是特别大,比较明显的是在这里的Subject写的比较简单,而Observable比较好用的是setChanged方法,这个方法能够有选择的给观察者们进行信息的传递,也让程序更加具有弹性。

但是!!!!!!!!!

在Java9的时候,Observer和Observable就已经废除了。在网上查询了一下废除的原因,主要有以下三个原因:

1、不能序列化

Observable没有实现Serializable接口,它的内部成员变量都是私有的。子类不能通过继承它来对Observable的成员变量处理,所以子类也不能序列化。

2、不是线程安全

在java.util.Observalble文档里没有强制要求Observable是线程安全的,它允许子类覆盖重写Observable的方法,事件通知无序以及事件通知发生在不同的线程里,这些都是会影响线程安全的问题。

3、支持事件模型的功能简单

支持事件模型的功能很简单,例如,只是支持事情发生变化的概念,但不能提供更多哪些内容发生了改变

解决方法:

利用java.beans里面的PropertyChangeEvent和PropertyChangeListener来代替Observer和Observable。

 

posted @   忠肝义胆-多隆  阅读(16)  评论(0编辑  收藏  举报
编辑推荐:
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· AI与.NET技术实操系列:向量存储与相似性搜索在 .NET 中的实现
阅读排行:
· 10年+ .NET Coder 心语 ── 封装的思维:从隐藏、稳定开始理解其本质意义
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· 提示词工程——AI应用必不可少的技术
· Open-Sora 2.0 重磅开源!
点击右上角即可分享
微信分享提示