观察者模式可以完美地将观察者和被观察者对象分开[1]。观察者模式,类似于订阅-发布模型:如报社提供报纸订阅的服务,居民购买报纸订阅的服务。报社和居民并不需要直接认识对方。但订阅报纸的居民,每天都能收到报社发布的日报。
Observer即订阅者的interface,Observable即订阅主题的抽象类。Observable(订阅主题)内通过List
如果ConcreteObservable是报社,那么Observer就是订阅报纸的居民。
Observer:
public interface Observer { void update(String msg); }
Observable:
public abstract class Observable { private ListmObserverList = new ArrayList<>(); public final void attach(Observer observer) { mObserverList.add(observer); } public final void detach(Observer observer) { mObserverList.remove(observer); } protected void notify(String msg) { for (Observer observer : mObserverList) { observer.update(msg); } } }
ConcreteObserver:
public class ConcreteObserver implements Observer { @Override public void update(String msg) { System.out.println("ConcreteObserver updage() msg: " + msg); } }
ConcreteObservable:
public class ConcreteObservable extends Observable { private String mMsg; public String getMsg() { return mMsg; } public void setMsg(String msg){ mMsg = msg; notify(msg); } }
Client:
public class Client { public static void main(String args[]) { ConcreteObservable paper = new ConcreteObservable(); ConcreteObserver resident0 = new ConcreteObserver(); ConcreteObserver resident1 = new ConcreteObserver(); paper.attach(resident0); paper.attach(resident1); paper.setMsg("papaer is sent"); } }
执行结果:
ConcreteObserver updage() msg: papaer is sent
ConcreteObserver updage() msg: papaer is sent
Java本身自带的观察者模式为:java.util.Observable和java.util.Observer。其基本原理,与之前实现的相似,但有很多细节,非常值得学习。
java.util.Observer:
public interface Observer { void update(Observable o, Object arg); }
java.util.Observable:
public class Observable {
// 判断Observable是否有变化
private boolean changed = false;
// 存储订阅者的引用
private Vector 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) {
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);
}
// 删除所有订阅者
public synchronized void deleteObservers() {
obs.removeAllElements();
}
// 设置changed为true
protected synchronized void setChanged() {
changed = true;
}
// 设置changed为false
protected synchronized void clearChanged() {
changed = false;
}
// 检查changed是否为true
public synchronized boolean hasChanged() {
return changed;
}
// 获取订阅者数量
public synchronized int countObservers() {
return obs.size();
}
}
可以看到,java.util.Observable使用的是Vector来存储Observers,很多方法都使用了“synchronized”关键字,保证了java.util.Observable的线程安全。通过changed的属性使用,使得notifyXXX被调用时,如果Observable并未真正发生变化时,Observer不会收到通知。
java.util.Observable和java.util.Observer的使用方式,与之前自己实现的Observable和Observer的使用方式,基本一样。除了以下两点:
(A) java.util.Observer可以得知发生变化的java.util.Observable具体类,而且,可传任意类型的参数。
(B) java.util.Observable需要通过setChanged()和clearChaged()来维护Observable具体类,是否真的发生了变化。
具体使用方式,就不再累述。使用有困难的同学,可以留言,大家一起讨论一下。
[1] 观察者模式_百度百科