简单地谈一下观察者模式

1022 查看

让我们来简单地谈一下观察者模式。

概念

这种模式有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,就是很好的一个使用观察者模式的例子。观察者模式引申出基于事件驱动的编程模型,使系统得到充分解耦。