Google Guava 是 Google 公司内部 Java 开发工具库的开源版本,它提供了一些新功能或对 JDK 已有功能的增强功能。其中就包括:集合(Collections)、缓存(Caching)、原生类型支持(Primitives Support)、并发库(Concurrency Libraries)、通用注解(Common Annotation)、字符串处理(Strings Processing)、数学计算(Math)、I/O、事件总线(EventBus)等等。

站内文章观察者模式:订阅与推送 文章中,我们介绍了观察者模式的同步阻塞的实现方式和异步非阻塞实现方式。本文将介绍使用 Google Guava EventBus 让观察者模式的实现过程更加灵活和简易,并亲自动手写一个简易版的 EventBus。

从观察者模式开始

使用 Google Guava EventBus 的观察者模式代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
public interface Subject {
void registerObserver(Object observer);
void removeObserver(Object observer);
void notifyObservers(Object message);
}

public class ConcreteSubject implements Subject {
private List<Object> observers = new ArrayList<Object>();
private EventBus eventBus;


public ConcreteSubject() {
// 同步阻塞模式
eventBus = new EventBus();
// 异步非阻塞模式
// eventBus = new AsyncEventBus(Executors.newFixedThreadPool(DEFAULT_EVENTBUS_THREAD_POOL_SIZE));
}

@Override
public void registerObserver(Object observer) {
eventBus.register(observer);
}

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

@Override
public void notifyObservers(Object message) {
eventBus.post(message);
}
}

利用 EventBus 框架实现的观察者模式,跟经典的同步阻塞观察者模式的代码相比,实现思路大致一样,都需要定义 Observer,并且通过 registerObserver() 函数注册 Observer,也都需要通过调用某个函数(比如,EventBus 中的 post() 函数)来给 Observer 发送消息(在 EventBus 中消息被称作事件 event)。

但在实现细节方面,它们又有些区别。基于 EventBus,我们不需要定义 Observer 接口,任意类型的对象都可以注册到 EventBus 中,通过 @Subscribe 注解来标明类中哪个函数可以接收被观察者发送的消息。

Guava EventBus 的结构与功能

Guava EventBus 对外暴露的所有可调用接口,都封装在 EventBus 类中。其中,EventBus 实现了同步阻塞的观察者模式,AsyncEventBus 继承自 EventBus,提供了异步非阻塞的观察者模式。

1
2
EventBus eventBus = new EventBus(); // 同步阻塞模式
EventBus eventBus = new AsyncEventBus(Executors.newFixedThreadPool(8));// 异步阻塞模式

EventBus 类提供了 register() 函数用来注册观察者。它可以接受任何类型(Object)的观察者。而在经典的观察者模式的实现中,register() 函数必须接受实现了同一 Observer 接口的类对象。post() 函数,用来给观察者发送消息。

1
2
3
public void register(Object object);
public void unregister(Object object);
public void post(Object event);

跟经典的观察者模式的不同之处在于,当我们调用 post() 函数发送消息的时候,并非把消息发送给所有的观察者,而是发送给可匹配的观察者。所谓可匹配指的是,能接收的消息类型是发送消息(post 函数定义中的 event)类型的父类。

1
2
3
4
5
6
7
// AObserver能接收的消息类型是XMsg,BObserver能接收的消息类型是YMsg,CObserver能接收的消息类型是ZMsg。
XMsg xMsg = new XMsg();
YMsg yMsg = new YMsg(); // XMsg是YMsg的父类。
ZMsg zMsg = new ZMsg();
post(xMsg); // => AObserver接收到消息
post(yMsg); // => AObserver、BObserver接收到消息
post(zMsg); // => CObserver接收到消息

EventBus 通过 @Subscribe 注解来标明,某个函数能接收哪种类型的消息。比如在下面的代码中,当通过 register() 函数将 DObserver 类对象注册到 EventBus 的时候,EventBus 会根据 @Subscribe 注解找到 f1()f2(),并且将两个函数能接收的消息类型记录下来(PMsg->f1QMsg->f2)。当我们通过 post() 函数发送消息(比如 QMsg 消息)的时候,EventBus 会通过之前的记录调用相应的函数 f2()

1
2
3
4
5
6
7
8
9
public DObserver {
//...省略其他属性和方法...

@Subscribe
public void f1(PMsg event) { /*...*/ }

@Subscribe
public void f2(QMsg event) { /*...*/ }
}

项目地址

示例项目:uuanqin/Simple-EvenBus: EvenBus 框架的简单实现

Readme Card

本文参考