Observer模式是行为模式之一,它的作用是当一个对象(我们称之为主题,Subject)的状态发生变化时,能够自动通知其他关联对象(我们称之为观察者,Observer)。通常情况下一个主题可以对应一个以上的观察者。实际中经常用在我们的事件模型中,例如AWT事件、Swing事件等等。
Observer模式的角色:
- Subject(主题,被观察者):被观察的对象。当主题的状态发生变化时,需要通知队列中所有观察者对象,因此Subject需要维持(添加,删除,通知)一个观察者对象的队列列表,这个列表中维护一个所有观察者对象,并在发生变化时通知他们。
- ConcreteSubject:被观察者的具体实现。包含一些基本的属性状态及其他操作。
- Observer(观察者):接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
- ConcreteObserver:观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。
JDK提供了对observer设计模式的支持:
- java.util.Observable类扮演Subject角色,一个类只需通过继承java.util.Observable类便可担当ConcreteSubject角色;
- java.util.Observer接口扮演Observer角色,一个类只需实现java.util.Observer接口便可担当ConcreteObserver角色。
- java.util.Observable的实现类通过调用setChanged()方法以及notifyObservers(Object)方法便可简单地通知Observer。
下面是一个简单的例子:
Subject已经被实现为Observable类,且Observer已经被实现为Observer接口,所以我们只需要实现ConcreteSubject和ConcreteObserver即可:
ConcreteSubject:
public class ConcreteSubject extends Observable {
public String str;
public void setStr(String str) {
this.str = str;
// 属性发生变更,需要设置change属性并通知所有的Observer对象
setChanged();
notifyObservers(str);
}
}
ConcreteObserver:
public class ConcreteObserver implements Observer {
@Override
public void update(Observable o, Object arg) {
// 被ConcreteSubject对象通知需要刷新
System.out.println("Parameter is " + (String)arg);
}
}
测试类:
public class ConsoleTest {
public static void main(String[] args) {
ConcreteSubject subject = new ConcreteSubject();
ConcreteObserver obj1 = new ConcreteObserver();
ConcreteObserver obj2 = new ConcreteObserver();
ConcreteObserver obj3 = new ConcreteObserver();
subject.addObserver(obj1);
subject.addObserver(obj2);
subject.addObserver(obj3);
subject.setStr("Hello");
}
}
我们再去看看源代码:
Subject的源代码:去掉注释后我们可以发现主要就是实现了add、delete、notify这几个主要的方法,这样我们普通的开发者就无需自己去实现这些,只要调用setChanged和notify即可。
package java.util;
public class 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) {
/*
* 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);
}
public synchronized void deleteObservers() {
obs.removeAllElements();
}
protected synchronized void setChanged() {
changed = true;
}
protected synchronized void clearChanged() {
changed = false;
}
public synchronized boolean hasChanged() {
return changed;
}
public synchronized int countObservers() {
return obs.size();
}
}
Observer代码更加简单:仅仅是一个接口,因为我们每个开发者需要实现不同的刷新方式。
package java.util;
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);
}
这样看下来整个Observer设计模式就没有那么神秘了。