观察者模式
概述
在系统中,对象并不是孤立存在的,一个对象的改变可能会导致其他与之存在依赖关系的对象发生改变。观察者模式用于描述对象之间的依赖关系,一个对象发生改变会自动通知其他对象,其他对象将相应做出反应。发生改变的对象称为观察目标,被通知的对象称为观察者,一个观察目标可以对应多个观察者,而且观察者之间没有相互联系
模式分析
观察者模式的关键对象是观察目标和观察者,一个目标可以有任意多个与之相依赖的观察者,一旦目标状态发生变化,所有观察者都将得到通知。作为对这个通知的响应,每个观察者都将即时更新自己的状态,与目标状态同步。目标是通知的发布者,它发出通知时不需要知道谁是它的观察者,可以有任意数目的观察订阅并接收通知。
抽象目标 Subject,典型代码如下
import java.util.*;
public abstract class Subject {
// 定义一个集合存储任意数量的观察者对象
protected ArrayList<Observer> observers = new ArrayList<Observer>();
// 增加一个观察者
public abstract void attach(Observer observer);
// 删除一个观察者
public abstract void detach(Observer observer);
// 通知各个观察者并调用它们的 update() 方法
public abstract void notifyObservers();
}
具体目标类 ConcreteSubject 是实现 Subject 的一个具体子类,典型代码如下
public class ConcreteSubject extends Subject {
// 向集合中添加一个观察者
public void attach(Observer observer) {
observers.add(observer);
}
// 从集合中删除一个观察者
public void detach(Observer observer) {
observers.remove(observer);
}
// 循环调用集合中观察者的 updates() 方法
public void notifyObservers() {
for (Observer obs : observers) {
obs.update();
}
}
}
也可以把 attach() 和 detach() 方法的实现放在 Subject 中,这样就无需每个子类都去实现一次了
抽象观察者一般定义为一个接口,其中声明 update() 方法,这个方法在其子类中实现,不同的观察者具有不同的更新响应方法,典型代码如下
public interface Observer {
public void update();
}
具体观察者 ConcreteObserver 中实现 update() 方法,其典型代码如下
public class ConcreteObserver implements Observer {
public void update() {
// 具体更新代码
}
}
在使用时,客户端首先创建具体目标对象以及具体观察者对象,然后,调用目标对象的 attach() 方法,将这个观察者对象在目标对象中登记,也就是将它加入到目标对象的观察者集合中
Subject subject = new ConcreteSubject();
Observer observer = new ConcreteObserver();
subject.attach(observer);
subject.notifyObservers();
客户端调用目标对象的 notifyObservers() 方法时,将调用在其观察者集合中注册的观察者对象的 update() 方法,实现状态的更新
在有些复杂的情况下,具体观察者类 ConcreteObserver 的 update() 方法在执行时,需要使用到 ConcreteSubject 中的状态(属性)
举个例子,我们经常会用可视化的图表(如柱状图、饼状图)来显示数据,同样的数据可能有不同的图表显示方法(即不同的具体观察者),如果数据发生改变(目标发生改变),图标也应该实时做出改变(观察者发生改变),那自然的,图表在更新时肯定需要用到新的数据
如果像上述而言,那么 ConcreteObserver 和 ConcreteSubject 之间还存在关联关系,在 ConcreteObserver 中定义一个 ConcreteSubject 实例,通过该实例获取存储在 ConcreteSubject 中的状态属性
// 具体目标类
public class ConcreteSubject extends Subject {
// 方便起见,attahch() 等抽象方法在抽象层做了实现了
// 具体目标类状态
private int state;
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
// 具体观察者类
public class ConcreteObserver implements Observer {
private Subject subject = new ConcreteSubject();
private int observerState;
public void update() {
observerState = subject.getState();
// 具体更新代码
}
}
Java 对观察者模式的支持
Java 提供了 Observable 类以及 Observer 接口,构成 Java 语言对观察者模式的支持
java.util.Observer 接口只定义一个方法,充当抽象观察者
public interface Observer {
void update(Observable o, Object arg);
}
当观察目标状态发生变化时,该方法将被调用,在 Observer 的实现子类实现该 update() 方法,即具体观察者可以根据需要有不同的更新行为。当调用观察目标类 Observable 的 notifyObservers() 方法时,将调用观察者类中的 update() 方法
java.util.Observable 类充当观察目标类,定义了一个向量 Vector 来存储观察者对象。标记变量 changed 表示观察目标是否发生变化,true 表示发生变化,false 则表示对象不再发生改变还已经通知了所有观察者对象,并调用了它们的 update() 方法
我们可以直接使用 Observer 接口和 Observable 类来作为观察者模式的抽象层,自定义具体的观察者类和观察目标类,更加方便地在 Java 语言中使用观察者模式