在G4的设计模式一书中,观察者模式是一种相对比较难以理解的模式,之所以难以理解,主要是由于单独看类图很难了解观察者和被观察者之间的通知关系。许多设计模式的书本在观察者模式这一章都是讲了一些开源框架中的观察者模式实现以方便读者理解,这篇文章我就以JDK源码中util包的Observable为主来简单说明下观察者模式。
既然要来讲解,首先我们要知道怎么使用,首先设计一个类继承Observable:
public class Publisher extends Observable {
public void publish(Object obj) {
setChanged();
notifyObservers(obj);
clearChanged();
}
}
这个类中需要设计一个通知观察者的方法,并同时调用父类的setChanged和notifiyObservers两个方法,调用完成以后最好再用clear方法来清除。
然后设计此类的对象,并给他设置观察者:
Publisher observable = new Publisher();
observable.addObserver(new Observer() {
@Override
public void update(Observable o, Object arg) {
System.out.println("1111" + arg);
}
});
observable.addObserver(new Observer() {
@Override
public void update(Observable o, Object arg) {
System.out.println("2222" + arg);
}
});
System.out.println("3333");
observable.publish("XXXX");
观察者需要实现Observer接口,由于和Observable类只差了几个字,所以稍微仔细区分一下,在给Observable对象设置了几个观察者以后,调用他的通知方法,其执行结果为:
3333
2222XXXX
1111XXXX
jdk给的观察者工具的使用方式就是这样,我们来看下他是怎么设计的,首先看下观察者接口Observer:
/**
* A class can implement the <code>Observer</code> interface when it
* wants to be informed of changes in observable objects.
*
* @author Chris Warth
* @see java.util.Observable
* @since JDK1.0
*/
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);
可以看到这里定义了一个操作:update,观察者可以实现这个操作来完成被观察者执行特定动作时候的处理,其中两个参数,第一个为观察者中介的Observable对象,第二个是传递的数据。
再来看Observable类的源码:
/**
* This class represents an observable object, or "data"
* in the model-view paradigm. It can be subclassed to represent an
* object that the application wants to have observed.
* <p>
* An observable object can have one or more observers. An observer
* may be any object that implements interface <tt>Observer</tt>. After an
* observable instance changes, an application calling the
* <code>Observable</code>'s <code>notifyObservers</code> method
* causes all of its observers to be notified of the change by a call
* to their <code>update</code> method.
* <p>
* The order in which notifications will be delivered is unspecified.
* The default implementation provided in the Observable class will
* notify Observers in the order in which they registered interest, but
* subclasses may change this order, use no guaranteed order, deliver
* notifications on separate threads, or may guarantee that their
* subclass follows this order, as they choose.
* <p>
* Note that this notification mechanism has nothing to do with threads
* and is completely separate from the <tt>wait</tt> and <tt>notify</tt>
* mechanism of class <tt>Object</tt>.
* <p>
* When an observable object is newly created, its set of observers is
* empty. Two observers are considered the same if and only if the
* <tt>equals</tt> method returns true for them.
*
* @author Chris Warth
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
* @see java.util.Observer
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
* @since JDK1.0
*/
public class Observable {
private boolean changed = false;
private Vector<Observer> obs;
/** Construct an Observable with zero Observers. */
public Observable() {
obs = new Vector<>();
}
类中定义了两个比较重要的元素obs和changed,分别表示了注册的观察者集合以及被观察者是否发生了变化,然后看下增删观察者的过程:
/**
* Adds an observer to the set of observers for this object, provided
* that it is not the same as some observer already in the set.
* The order in which notifications will be delivered to multiple
* observers is not specified. See the class comment.
*
* @param o an observer to be added.
* @throws NullPointerException if the parameter o is null.
*/
public synchronized void addObserver(Observer o) {
if (o == null)
throw new NullPointerException();
if (!obs.contains(o)) {
obs.addElement(o);
}
}
/**
* Deletes an observer from the set of observers of this object.
* Passing <CODE>null</CODE> to this method will have no effect.
* @param o the observer to be deleted.
*/
public synchronized void deleteObserver(Observer o) {
obs.removeElement(o);
}
这段代码并不难理解,然后我们看通知观察者的方法:
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to
* indicate that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and <code>null</code>. In other
* words, this method is equivalent to:
* <blockquote><tt>
* notifyObservers(null)</tt></blockquote>
*
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
public void notifyObservers() {
notifyObservers(null);
}
/**
* If this object has changed, as indicated by the
* <code>hasChanged</code> method, then notify all of its observers
* and then call the <code>clearChanged</code> method to indicate
* that this object has no longer changed.
* <p>
* Each observer has its <code>update</code> method called with two
* arguments: this observable object and the <code>arg</code> argument.
*
* @param arg any object.
* @see java.util.Observable#clearChanged()
* @see java.util.Observable#hasChanged()
* @see java.util.Observer#update(java.util.Observable, java.lang.Object)
*/
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);
}
这里我们可以看到,如果changed并没有被设置成为true,是没有办法做出通知的,然后我们看下设置changed值的方法:
/**
* Marks this <tt>Observable</tt> object as having been changed; the
* <tt>hasChanged</tt> method will now return <tt>true</tt>.
*/
protected synchronized void setChanged() {
changed = true;
}
/**
* Indicates that this object has no longer changed, or that it has
* already notified all of its observers of its most recent change,
* so that the <tt>hasChanged</tt> method will now return <tt>false</tt>.
* This method is called automatically by the
* <code>notifyObservers</code> methods.
*
* @see java.util.Observable#notifyObservers()
* @see java.util.Observable#notifyObservers(java.lang.Object)
*/
protected synchronized void clearChanged() {
changed = false;
}
这里把这两个方法设计成为了protected,虽然不清楚设计者的具体意图,但是个人感觉是为了强制开发人员将通知观察者的详细实现设计在子类的方法中。
好,这段源码的解读之后相信大家对观察者有点小小的了解了,其实java有个非常出名的类库rxJava,这个类库据我的经验在android开发中尤其多,他不仅完成了观察者模式,最关键的是他可以完成线性操作、异步处理、线程转化控制等多个特别功能,这个类库的代码量比java.util包中的这个Observable类要庞大的多,为了省去篇幅这里就不细讲了,有兴趣可以自己去阅读。