观察者模式,又叫发布-订阅(Publish/Subscribe)模式,它定义了对象之间一对多的依赖关系,当一个对象状态改变时,其他相关联的对象就会得到通知并被自动更新。

例如,现有一组数据,分别画出柱状图、饼状图、折线图,当数据发生变化时,图形也需要同时进行相应的变化。

观察者模式_对象状态

如图所示,监听的对象叫观察者(Observer),被监听的对象叫被观察者(Observable,也称主题Subject)。被观察者对象在状态上发生变化时,会通知所有观察者对象,使它们能够做出相应的变化。

观察者模式的实现方法可以有我们自己确定,Java也提供了对观察者模式的内置支持,java.util.Observable 类和 java.util.Observer 接口。虽然内置的方式不够灵活,有一些限制,但能够帮助我们理解和使用观察者模式。

Observer接口

public interface Observer {
void update(Observable o, Object arg);
}

这个接口只定义了一个update()方法,当被观察者对象的状态发生变化时,这个方法就会被调用。

Observable类(摘取部分)

public class Observable {
private boolean changed = false;
private Vector<Observer> obs;

public Observable() {
obs = new Vector<>();
}

public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}

public void notifyObservers() {
notifyObservers(null);
}

public void notifyObservers(Object arg) {
Object[] arrLocal;
synchronized (this) {
if (!changed)
return;
arrLocal = obs.toArray();
clearChanged();
}

for (int i = arrLocal.length-1; i>=0; i--)
((Observer)arrLocal[i]).update(this, arg);
}

protected synchronized void setChanged() {
changed = true;
}
}

通过调用 addObserver 方法,将对象加入到列表中,setChanged 方法用来设置一个标记变量,代表被观察者对象的状态发生了变化,notifyObservers 方法被调用时,会调用所有添加的观察者的 update() 方法。


观察者模式示例

被观察者

public class Data extends Observable {
private int[] array;

public Data() {
array = new int[20];
}

public void change(int position, int value) {
array[position] = value;
setChanged();
}
}

观察者

public class Graph implements Observer{
@Override
public void update(Observable o, Object arg) {
System.out.println("重新绘制数据!");
}
}

测试

public class ObserverDemo {
public static void main(String[] args) {
Data data = new Data();
Graph graph = new Graph();
data.addObserver(graph);
data.change(0, 1);
data.notifyObservers();
}
}

输出结果:

重新绘制数据!