观察者模式
观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态上发生变化时,会通知所有观察者对象,使它们能够自动更新自己。
观察者模式是对象的行为模式,又叫发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。
模式结构
模式涉及角色
抽象被观察者:持有观察者的引用和被观察者状态标记,包括一些添加,删除,通知观察者的方法等。
抽象观察者:有一个回调 update 方法。
具体被观察者:对抽象被观察者的实现。
具体观察者:对抽象观察者的实现,回调 update 方法实现。
模式结构图
(图片来自网络,侵删)
示例
因为 Java 的 jdk 中已经有观察者模式的工具类,所以以 jdk 中的观察者模式为例。jdk 中已经定义好了被观察者类 Observable 和观察者接口 Observer。Observable 类中有记录状态属性和持有观察者引用的向量,然后是一些添加,删除,通知观察者的方法,值得注意的是只有被观察者对象的状态发生变化时,才会回调观察者的 update 方法,见方法 public void notifyObservers(Object arg)
实现代码。
代码实现
被观察者类 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 synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
//通知观察者
public void notifyObservers() {
notifyObservers(null);
}
public void notifyObservers(Object arg) {
/*
* a temporary array buffer, used as a snapshot of the state of
* current Observers.
*/
Object[] arrLocal;
synchronized (this) {
/* We don't want the Observer doing callbacks into
* arbitrary code while holding its own Monitor.
* The code where we extract each Observable from
* the Vector and store the state of the Observer
* needs synchronization, but notifying observers
* does not (should not). The worst result of any
* potential race-condition here is that:
* 1) a newly-added Observer will miss a
* notification in progress
* 2) a recently unregistered Observer will be
* wrongly notified when it doesn't care
*/
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;
}
//***其他方法就不在罗列了
观察者接口 Observer
public interface Observer {
/**
* This method is called whenever the observed object is changed. An
* application calls an <tt>Observable</tt> object's
* <code>notifyObservers</code> method to have all the object's
* observers notified of the change.
*
* @param o the observable object.
* @param arg an argument passed to the <code>notifyObservers</code>
* method.
*/
void update(Observable o, Object arg);
}
具体被观察者类 ConcreteObservable
/**
* 具体被观察者
*/
class ConcreteObservable extends Observable{
public ConcreteObservable(){
super();
setChanged();
}
}
两个具体的观察者类 ConcreteObserver1,ConcreteObserver2
/**
* 具体观察者
*/
class ConcreteObserver1 implements Observer{
@Override
public void update(Observable observable, Object object){
System.out.println("观察者ConcreteObserver1 状态: " + object.toString());
}
}
class ConcreteObserver2 implements Observer{
@Override
public void update(Observable observable, Object object){
System.out.println("观察者ConcreteObserver2 状态: " + object.toString());
}
}
测试代码
public class ObserverPattern {
public static void main(String[] args){
ConcreteObservable observable = new ConcreteObservable();
ConcreteObserver1 concreteObserver1 = new ConcreteObserver1();
ConcreteObserver2 concreteObserver2 = new ConcreteObserver2();
observable.addObserver(concreteObserver1);
observable.addObserver(concreteObserver2);
observable.notifyObservers("状态发生变化,新状态是 ABC");
}
}
其实看着这个代码很容易想起之前写的 Java——回调机制,其实观察者模式也是回调的一种实现,可以看到被观察者类 Observable 持有观察者引用的向量 private Vector<Observer> obs;
,当被观察者状态发生变化时,会通过这些已经注册的观察者,回调观察者的 void update(Observable o, Object arg);
方法。
示例 demo 见:https://github.com/lzx2011/java-scaffold
运行结果
观察者ConcreteObserver2 状态: 状态发生变化,新状态是 ABC
观察者ConcreteObserver1 状态: 状态发生变化,新状态是 ABC
应用场景
当一个对象改变时,同时需要改变其他对象,应考虑使用观察者模式。