简单地说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象。这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的
那些观察者对象,使这些观察者对象能够自动更新。
一、观察者模式的结构
本模式的类图结构如下:
![]() 图1、观察者模式的静态结构可从类图中看清楚。 |
在观察者模式里有如下的角色:
. 抽象主题(Subject)角色:主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;
![]() 图2、抽象主题角色,有时又叫做抽象被观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。 |
. 抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到通知时更新自己;
![]() 图3、抽象观察者角色,可以用一个抽象类或者一个接口实现;在具体的情况下也不排除使用具体类实现。 |
. 具体主题(ConcreteSubject)角色:保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;
![]() 图4、具体主题角色,通常用一个具体子类实现。 |
.具体观察者(ConcreteObserver)角色:保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。
![]() 图5、具体观察者角色,通常用一个具体子类实现。 |
二、示意性实现的Java代码
首先在这个示意性的实现里,用一个Java接口实现抽象主题角色,这就是下面的Subject接口:
public interface Subject { public void attach(Observer observer); public void detach(Observer observer); void notifyObservers(); } |
import java.util.Vector; import java.util.Enumeration; public class ConcreteSubject implements Subject { private Vector observersVector = new java.util.Vector(); public void attach(Observer observer) { //添加观察者 observersVector.addElement(observer); } public void detach(Observer observer) { //删除该观察者 observersVector.removeElement(observer); } public void notifyObservers() { //遍历观察者向量,通知每个观察者 Enumeration enumeration = observers(); while (enumeration.hasMoreElements()) { ((Observer)enumeration.nextElement()).update(); } } public Enumeration observers() { return ((Vector) observersVector.clone()).elements(); } } |
public interface Observer { void update(); } |
public class ConcreteObserver implements Observer { public void update() { // Write your code here,一般来说Observer还有一个指向主题的引用,在这个方法中可以通过它,来判断自己关注的数据是否发生变化,并作出相应的行动 } } |
代码清单4、ConcreteObserver类的源代码。
三、Java语言提供的对观察者模式的支持
虽然观察者模式的实现方法可以有设计师自己确定,但是因为从AWT1.1开始视窗系统的事件模型采用观察者模式,因此观察者模式在Java语言里的地 位较为重要。正因为这个原因,Java语言给出了它自己对观察者模式的支持。因此,本文建议读者在自己的系统中应用观察者模式时,不妨利用Java语言所 提供的支持。
在Java语言的java.util库里面,提供了一个Observable类以及一个Observer接口,构成Java语言对观察者模式的支持。
Observer接口
这个接口只定义了一个方法,update()。当被观察者对象的状态发生变化时,这个方法就会被调用。这个方法的实现应当调用每一个被观察者对象的notifyObservers()方法,从而通知所有的观察对象。
![]() 图6、java.util提供的Observer接口的类图。 |
package java.util; public interface Observer { /** * 当被观察的对象发生变化时,这个方法会被调用。 */ void update(Observable o, Object arg); } |
![]() 图7、Java语言提供的被观察者的类图。 |
![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() ![]() |
![]() 图8、使用Java语言提供的对观察者模式的支持。 |
发通知的次序在这里没有指明。Observerable类所提供的缺省实现会按照Observers对象被登记的次序通知它们,但是Observerable类的子类可以改掉这一次序。子类并可以在单独的线程里通知观察者对象;或者在一个公用的线程里按照次序执行。
当一个可观察者对象刚刚创立时,它的观察者集合是空的。两个观察者对象在它们的equals()方法返回true时,被认为是两个相等的对象。