What
观察者模式(Observer Design Pattern)也被称为发布订阅模式(Publish-Subscribe Design Pattern)。
Define a one-to-many dependency between objects so that when one object changes state, all its dependents are notified and updated automatically.
在对象之间定义一对多的依赖,当一个对象状态改变的时候,所有依赖的对象都会自动收到通知。实现解耦观察者和被观察者。
How
同步阻塞式
同步阻塞是最经典的实现方式,主要是为了代码解耦。
/**
* 同步阻塞式
* 最经典的实现方式
*
* @author yiy
* @date 12/28/2021
*/
public class SynchronousBlockingWay {
public static void main(String[] args) {
ISubject subject = new ConcreteSubject();
subject.registerObserver(new ObserverOne());
subject.registerObserver(new ObserverTwo());
subject.message("通知的消息");
}
}
/**
* 观察者接口
*/
interface IObserver {
/**
* 发送和接收消息的接口
*
* @param message
*/
void message(String message);
}
/**
* 主题接口
* <p>
* 注意:经典的实现方式中并未将主题接口去继承观察者接口,
* 即 是将消息发送和接收的接口分开的,但必须要保证这两个接口的参数签名要一致,那么我为何不将接口名更抽象一下,使用继承来保证参数签名的一致呢?我个人觉得这样更好!
*/
interface ISubject extends IObserver {
/**
* 注册观察者
*
* @param observer
*/
void registerObserver(IObserver observer);
/**
* 注销观察者
*
* @param observer
*/
void removeObserver(IObserver observer);
}
/**
* 观察者1
*/
class ObserverOne implements IObserver {
@Override
public void message(String message) {
//获取消息通知,执行自己的逻辑...
System.out.println("ObserverOne is notified-->" + message + " ");
}
}
/**
* 观察者2
*/
class ObserverTwo implements IObserver {
@Override
public void message(String message) {
//获取消息通知,执行自己的逻辑...
System.out.println("ObserverTwo is notified-->" + message + " ");
}
}
/**
* 主题实例
*/
class ConcreteSubject implements ISubject {
private List<IObserver> observers = new ArrayList<>();
@Override
public void registerObserver(IObserver observer) {
observers.add(observer);
}
@Override
public void removeObserver(IObserver observer) {
observers.remove(observer);
}
@Override
public void message(String message) {
for (IObserver observer : observers) {
observer.message(message);
}
}
}
异步非阻塞式
异步非阻塞除了能实现代码解耦之外,还能提高代码的执行效率。本质上是在观察者收到消息后的执行逻辑通过另起线程来执行实现。
可以通过大名鼎鼎的Google的开源框架Google Guava EventBus来实现,具体原理与使用请查看原稿。
/**
* 异步非阻塞方式
* <p>
* 异步非阻塞除了能实现代码解耦之外,还能提高代码的执行效率。本质上是在观察者收到消息后的执行逻辑通过另起线程来执行实现异步。
* 下面通过大名鼎鼎的Google的开源框架Google Guava EventBus来实现
* <p>
* 利用 EventBus 框架实现的观察者模式,跟从零开始编写的观察者模式相比,从大的流程上来说,实现思路大致一样,都需要定义 Observer,并且通过 register() 函数注册 Observer,也都需要通过调用某个函数(比如,EventBus 中的 post() 函数)来给 Observer 发送消息(在 EventBus 中消息被称作事件 event);
* 但在实现细节方面,它们又有些区别。基于 EventBus,我们不需要定义 Observer 接口,任意类型的对象都可以注册到 EventBus 中,通过 @Subscribe 注解来标明类中哪个函数可以接收被观察者发送的消息。
*
* @author yiy
* @date 12/28/2021
*/
public class AsynchronousNonblockingWay {
public static void main(String[] args) {
EventBus eventBus = EventBusUtil.eventBusAsy;
eventBus.register(new Observer1());
eventBus.register(new Observer2());
/*
调用 post() 函数发送消息的时候,并非把消息发送给所有的观察者,而是发送给可匹配的观察者;
即 能接收的消息类型是发送消息(post 函数定义中的 event)类型的父类。
*/
eventBus.post(1);
}
}
/**
* EventBus工具类
*/
class EventBusUtil {
/**
* 同步的EventBus
*/
public static EventBus eventBus = new EventBus();
/**
* 异步的EventBus
*/
public static EventBus eventBusAsy = new AsyncEventBus(Executors.newFixedThreadPool(20));
}
/**
* 观察者1
*/
class Observer1 {
@Subscribe
public void update(String message) {
//获取消息通知,执行自己的逻辑...
System.out.println("Observer1 is notified-->" + message + " ");
}
}
/**
* 观察者2
*/
class Observer2 {
@Subscribe
public void update(String message) {
//获取消息通知,执行自己的逻辑...
System.out.println("Observer2 is notified-->" + message + " ");
}
}
跨进程式
进程间的观察者模式解耦更加彻底,一般是基于消息队列来实现,用来实现不同进程间的被观察者和观察者之间的交互。