让我们来简单地谈一下观察者模式。
概念
这种模式有2个主要的客体,一个是被观察者(Observable),也可以称为生产者;一个是观察者(Observer),也可以称为消费者。
观察者关心被观察者掌握的数据,称为“订阅”
被观察者可能掌握着多个不同的数据,被不同的观察者所关心,怎么区分不同的数据和订阅关系?这称为“Topic”
被观察者怎么才能通知到观察者?
被观察者会维护一个不同topic的观察者列表。在JDK中,Observable类会维护一个观察者的Vector列表;而在分布式系统中,这通常被称为“路由规则”;在面对海量观察者的时候,这又涉及到“推拉模式”的选择和“数据的分片”传输,这其实也就是消息中间件主要需要解决的问题。
这个模式有什么用?
松耦合、异步化。
松耦合、异步化有什么用?我可以让锅在饭熟了的时候告诉我,而不用我一直盯着锅里看饭有没有熟,我可以先去看看电视,是不是很强大?
看看源码
JDK自带的观察者模式实现类源码简单看下,不过已经过时不太建议使用了:
被观察者要继承一个Observable类:
public class Observable {
private boolean changed = false;
private Vector obs;
...
为啥要用线程安全的Vector?因为观察者列表需要动态修改的,例如:
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
同时用到了synchronized关键字,并发修改必须排队。Vector内部也用到了重量级锁:
public synchronized boolean removeElement(Object obj) {
modCount++;
int i = indexOf(obj);
if (i >= 0) {
removeElementAt(i);
return true;
}
return false;
}
所以慎用,特别是高并发场景,小心死锁。同时效率也不高的,所以不推荐使用了。可以自己用concurrent包的一些并发框架重新实现一把。
小结
分布式环境的观察者模式,其实就是消息中间件。单机内观察者模式的应用场景较少,不过在网络层,基于NIO设计的channel,就是很好的一个使用观察者模式的例子。观察者模式引申出基于事件驱动的编程模型,使系统得到充分解耦。