定义

定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。

主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。

类关系

主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。

观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。

1、创建主题定义

1
2
3
4
5
6
7
8
9
public interface Subject {

// 订阅
void subscribe(EventListener eventListener);
// 取消订阅
void unsubscribe(EventListener eventListener);
// 通知观察者
void notifyObserver();
}

2、定义具体主题

创建主题的具体实现,并且构建一个容器来维护订阅关系,支持添加删除关系,以及通知订阅者。

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
public class ConcreteSubject implements Subject{

private List<EventListener> observers = new ArrayList<>();

public void doSomething(){
System.out.println("具体主题业务逻辑实现");
notifyObserver();
}

@Override
public void subscribe(EventListener eventListener) {
observers.add(eventListener);
}

@Override
public void unsubscribe(EventListener eventListener) {
observers.remove(eventListener);
}

@Override
public void notifyObserver() {
for (EventListener eventListener : observers){
eventListener.doEvent();
}
}
}

3、定义观察者(事件监听者)

1
2
3
4
public interface EventListener {
// 执行事件
void doEvent();
}

4、观察者实现

1
2
3
4
5
6
public class EventListenerImplA implements EventListener{
@Override
public void doEvent() {
System.out.println("观察者 A 监听事件");
}
}
1
2
3
4
5
6
public class EventListenerImplB implements EventListener{
@Override
public void doEvent() {
System.out.println("观察者 B 监听事件");
}
}

5、客户端测试

1
2
3
4
5
6
7
8
9
public class Client {

public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
subject.subscribe(new EventListenerImplA());
subject.subscribe(new EventListenerImplB());
subject.doSomething();
}
}

总结

一般在开发中会把主线流程开发完成后,再使用通知的方式处理辅助流程。他们可以是异步的,在MQ以及定时任务的处理下,保证最终一致性。

观察者模式达到了解耦合的效果,减少了依赖关系,每个观察者根本不需要知道发布者处理了什么业务逻辑,也不用依赖发布者任何业务模型,只关心自己本身需要处理的逻辑就可以了。

如果有新的业务添加进来,我们也只需要创建一个新的订阅者,并且维护到observers 容器中即可,也符合我们的开闭原则。

这里只是一种同步的实现方式,我们还可以扩展更多其他的异步实现方式,或者采用多线程等实现方式。

参考资料

观察者模式 (qq.com)