【设计模式】观察者模式

92 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第2天,点击查看活动详情

前言

观察者模式归属于行为型设计模式,而行为型设计模式主要解决的是“类或对象之间的交互问题”。 观察者模式也被称为发布订阅者模式。

在 GoF 的《设计模式》一书中,它的定义是这样的:

Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.

翻译成中文即为:在对象间定义了一个一对多的依赖,但这个对象改变状态的时候,所有它的依赖者都会收到通知,并自动更新。

一般情况下,被依赖的对象叫作被观察者(Observable),依赖的对象叫作观察者(Observer)。但也有其他的叫法,比如:Subject-Observer、Publisher-Subscriber、Producer-Consumer、EventEmitter-EventListener、Dispatcher-Listener。

根据应用场景的不同,观察者模式会有不同的代码实现方式:

  1. 同步阻塞的、异步非阻塞的
  2. 进程内的实现方式、跨进程的实现方式
  3. ....

同步阻塞的观察者模式

被观察者

被观察者,或者可以称为事件的发送者。

根据定义,可以比较容易得出被观察者要做的事情:

  1. 注册/添加 观察者
  2. 当事件发生时,通知观察者
  3. 有添加就有删除,所以还应该有一个删除观察者
interface Subject{
    void registerObserver(Observer observer);
    void notifyObserver(Data data);
    void removeObserver(Observer observer);
}
class SubjectImpl implements Subject{
    private List<Observer> observers=new ArrayList<>();
    @Override
    public void registerObserver(Observer observer) {
        observers.add(observer);
    }

    @Override
    public void notifyObserver(Data data) {
        for(Observer observer:observers){
            observer.update(data);
        }
    }

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

观察者

观察者,或者可以称为事件的接收者。

当对应事件变更的时候,会收到通知并进行自动更新

interface Observer{
    void update(Data data);
}
class ObserverImpl_1 implements Observer{
    @Override
    public void update(Data data) {
        System.out.println("ObserverImpl_1,收到***"+data.getData());
    }
}
class ObserverImpl_2 implements Observer{
    @Override
    public void update(Data data) {
        System.out.println("ObserverImpl_2,收到***"+data.getData());
    }
}

传递的数据/信息

class Data{
    private String data;
    Data(){

    }
    Data(String str){
        this.data=str;
    }
    public String getData() {
        return data;
    }
    public void setData(String data) {
        this.data = data;
    }
}

测试/示例

public class Demo {
    public static void main(String[] args) {
        Observer observer_1 = new ObserverImpl_1(); // 观察者1号
        Observer observer_2 = new ObserverImpl_2(); // 观察者2号
        Subject subject = new SubjectImpl();        // 被观察者
        subject.registerObserver(observer_1);
        subject.registerObserver(observer_2);
        subject.notifyObserver(new Data("数据已发送变更"));
    }
}

异步非阻塞的观察者模式

如果只是做一个简单的实现,不考虑通用性、扩展性什么的,那么只需要在上述同步阻塞的观察者模式下,做些许的改动即可。有两种方案可以实现。

  1. 在Observer#update(...)方法中创建一个线程异步的去执行更新逻辑。
  2. 在调用被观察者的notifyObserver(...)方法时,创建一个线程池,异步的去执行Observer#update(...)方法。

分析: 第一种方法会使得线程创建的数量不可控,而且过多的线程创建和销毁势必会导致性能问题。 第二种方法虽然通过线程池使得线程的数量和创建、销毁可控了。但是问题在于,其把线程池的创建、调用等逻辑耦合在了被观察者。如果项目想要复用这个异步非阻塞的观察者模式,那么势必又要在新的被观察者里添加线程池、调用线程池【重复操作】。

EventBus 框架

EventBus 翻译为“事件总线”,它提供了实现观察者模式的骨架代码。基于此框架,我们可以非常容易地在自己的业务场景中实现观察者模式,不需要从零开始开发。 其中,Google Guava EventBus 就是一个比较著名的 EventBus 框架,它不仅仅支持异步非阻塞模式,同时也支持同步阻塞模式

Google Guava EventBus的github地址:github.com/google/guav…

我自己造的轮子已经写到了个人的gitee上:刷刷/shuashua-blog

这个轮子目前还不支持构造带有泛型参数的观察者方法,不然会出错

参考

57 | 观察者模式(下):如何实现一个异步非阻塞的EventBus框架?-极客时间