有两种方式来查看观察者设计模式的细节。第一种办法是了解定义在java.util的Observer和Observable类。第二种方法是研究注册事件监听器的JavaBeans组件模型。
在创建JavaBeans事件模型之前,Observer和Observable类就描述了观察者涉及模式的实现。换句话说,自从Java平台1.0版本,这些类就已经存在了。由于这些类在设计上并没有什么技术错误,因此一直沿用下来了。这些类现在还可以用于实现观察者模式,但是用的更多的是JavaBeans事件模型。使用Observer和Observable实现观察者模式存在一个问题就是你必须要扩展Observable类,这就强迫使用这样的类结构了,因为Java平台是只允许单继承的。
在事件注册监听器的JavaBeans组件模型中包含了一系列的添加和删除方法,方法的名称中包含了监听器的类型。例如,想要监听按钮的选择,你需要注册ActionListener,如下:
ActionListener listener = new ActionListener() {
public void actionPerformed(ActionEvent actionEvent) {
...
}
};
JButton button = new JButton("Pick Me");
button.addActionListener(listener);
在这里,我们实现一个监听器接口,将其附加到监听的对象上。监听的对象就是被监听的。它的职责是记住谁在监听,在JavaBeans组件模型中,用于附加和解除Observer对象的接口是添加和删除监听器命名模式。当监听对象的状态改变的时候,它会通知Observer对象。
这种设计模式的一个主要目标就是将对象和观察者的耦合度降低。当JButton被选择的时候,并非调用一个叫做ButtonNotification类的特定方法,通知动作被抽象到一个接口中,任何类都可以实现它。JButton并不关心绑定的监听器是什么。事实上,按钮不关心实现类是不是被修改了。它关心的是观察者实现了这个监听器。
在使用观察者模式的时候,有很多的复杂问题需要注意。首先是可能出现内存泄露。监听的对象维护着一个观察者的引用。在监听对象释放这个引用之前,垃圾收集器都不能删除观察者。一定要清醒的认识到这种可能,在合适的时候删除掉观察者。另外需要注意的是观察者对象维持在一个无序的集合之中。至少当注册监听器的时候是这样。你没有必要知道先被注册的监听器是先被调用还是后被调用。如果你需要有序的调用,例如A必须先被调用然后是B。那么你必须引入一个中间层的对象来强制这种顺序。简单的按照顺序来注册监听器是不能确保调用顺序的。
在Java平台中,另一个使用观察着模式的地方是Java消息服务(Java Message Service,JMS)。JMS的公共订购消息模型允许任何数量的订购者监听感兴趣的题目。当公共标题的信息产生的时候,所有相关的订购者都会被通知。
在Java平台的其他地方也都用到了观察者模式,可见这一设计模式在这个领域广泛采用着。