设计模式之观察者模式(Observer)
?简单的说,观察者模式定义了一个一对多的依赖关系,让一个或多个观察者对象监察一个主题对象。这样一个主题对象在状态上的变化能够通知所有的依赖于此对象的那些观察者对象,使这些观察者对象能够自动更新。
观察者模式的结构
观察者(Observer)模式是对象的行为型模式,又叫做发表-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-收听者(Source/Listener)模式或从属者(Dependents)模式。
本模式的类图结构如下:
图1、观察者模式的静态结构可从类图中看清楚。
在观察者模式里有如下的角色:
.?抽象主题(Subject)角色:主题角色把所有的观察者对象的引用保存在一个列表里;每个主题都可以有任何数量的观察者。主题提供一个接口可以加上或撤销观察者对象;主题角色又叫做抽象被观察者(Observable)角色;?

.?抽象观察者(Observer)角色:为所有的具体观察者定义一个接口,在得到通知时更新自己;?

.?具体主题(ConcreteSubject)角色:保存对具体观察者对象有用的内部状态;在这种内部状态改变时给其观察者发出一个通知;具体主题角色又叫作具体被观察者角色;

.具体观察者(ConcreteObserver)角色:保存一个指向具体主题对象的引用;和一个与主题的状态相符的状态。具体观察者角色实现抽象观察者角色所要求的更新自己的接口,以便使本身的状态与主题的状态自恰。?

下面给出一个示意性实现的Java代码。首先在这个示意性的实现里,用一个Java接口实现抽象主题角色,这就是下面的Subject接口:



package?java.util;
public?class?Observable
{
private?boolean?changed?=?false;
private?Vector?obs;
/**?用0个观察者构造一个被观察者。**/
public?Observable()
{
obs?=?new?Vector();
}
/**
*?将一个观察者加到观察者列表上面。
*/
public?synchronized?void?addObserver(Observer?o)
{
if?(!obs.contains(o))
{
obs.addElement(o);
}
}
/**
*?将一个观察者对象从观察者列表上删除。
*/
public?synchronized?void?deleteObserver(Observer?o)
{
obs.removeElement(o);
}
/**
*?相当于?notifyObservers(null)
*/
public?void?notifyObservers()
{
notifyObservers(null);
}
/**
*?如果本对象有变化(那时hasChanged?方法会返回true)
*?调用本方法通知所有登记在案的观察者,即调用它们的update()方法,
*?传入this和arg作为参量。
*/
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();
}
/**
*?将“已变化”设为true
*/
protected?synchronized?void?setChanged()
{
changed?=?true;
}
/**
*?将“已变化”重置为false
*/
protected?synchronized?void?clearChanged()
{
changed?=?false;
}
/**
*?探测本对象是否已变化
*/
public?synchronized?boolean?hasChanged()
{
return?changed;
}
/**
*?返还被观察对象(即此对象)的观察者总数。
*/
public?synchronized?int?countObservers()
{
return?obs.size();
}
}
代码清单6、java.util.Observer接口的源代码。?

package?com.javapatterns.observer.watching;
import?java.util.Observer;
public?class?Tester
{
static?private?Watched?watched;
static?private?Observer?watcher;
public?static?void?main(String[]?args)
{
watched?=?new?Watched();
watcher?=?new?Watcher(watched);
watched.changeData("In?C,?we?create?bugs.");
watched.changeData("In?Java,?we?inherit?bugs.");
watched.changeData("In?Java,?we?inherit?bugs.");
watched.changeData("In?Visual?Basic,?we?visualize?bugs.");?
}
}
package?com.javapatterns.observer.watching;
import?java.util.Observable;
public?class?Watched?extends?Observable
{
private?String?data?=?"";
public?String?retrieveData()
{
return?data;
}
public?void?changeData(String?data)
{
if?(?!this.data.equals(?data)?)
{
this.data?=?data;
setChanged();
}
notifyObservers();
}
}
package?com.javapatterns.observer.watching;
import?java.util.Observable;
import?java.util.Observer;
public?class?Watcher?implements?Observer
{
public?Watcher(Watched?w)
{
w.addObserver(this);
}
public?void?update(?Observable?ob,?Object?arg)
{
System.out.println("Data?has?been?changed?to:?'"?+?((Watched)ob).retrieveData()?+?"'");
}
}
watched.changeData("In?C,?we?create?bugs.");
watched.changeData("In?Java,?we?inherit?bugs.");
watched.changeData("In?Java,?we?inherit?bugs.");
watched.changeData("In?Visual?Basic,?we?visualize?bugs.");?
Data?has?been?changed?to:?'In?C,?we?create?bugs.'
Data?has?been?changed?to:?'In?Java,?we?inherit?bugs.'
Data?has?been?changed?to:?'In?Visual?Basic,?we?visualize?bugs.'
Java中的DEM事件机制
AWT中的DEM机制
AWT1.0的事件处理的模型是基于责任链的。这种模型不适用于复杂的系统,因此在AWT1.1版本及以后的各个版本中,事件处理模型均为基于观察者模式的委派事件模型(Delegation Event Model或DEM)。?
在DEM模型里面,主题(Subject)角色负责发布(publish)事件,而观察者角色向特定的主题订阅(subscribe)它所感兴趣的事件。当一个具体主题产生一个事件时,它就会通知所有感兴趣的订阅者。?
使用这种发布-订阅机制的基本设计目标,是提供一种将发布者与订阅者松散地耦合在一起的联系形式,以及一种能够动态地登记、取消向一个发布者的订阅请求的办法。显然,实现这一构思的技巧,是设计抽象接口,并把抽象层和具体层分开。这在观察者模式里可以清楚地看到。?
使用DEM的用词,发布者叫做事件源(event source),而订阅者叫做事件聆听者(event listener)。在Java里面,事件由类代表,事件的发布是通过同步地调用成员方法做到的。?
Servlet技术中的的DEM机制
AWT中所使用的DEM事件模型实际上被应用到了所有的Java事件机制上。Servlet技术中的事件处理机制同样也是使用的DEM模型。?
SAX2技术中的DEM机制
DEM事件模型也被应用到了SAX2的事件处理机制上。?
观察者模式的效果
观察者模式的效果有以下的优点:?
第一、观察者模式在被观察者和观察者之间建立一个抽象的耦合。被观察者角色所知道的只是一个具体观察者列表,每一个具体观察者都符合一个抽象观察者的接口。被观察者并不认识任何一个具体观察者,它只知道它们都有一个共同的接口。?
由于被观察者和观察者没有紧密地耦合在一起,因此它们可以属于不同的抽象化层次。如果被观察者和观察者都被扔到一起,那么这个对象必然跨越抽象化和具体化层次。?
第二、观察者模式支持广播通讯。被观察者会向所有的登记过的观察者发出通知,?
观察者模式有下面的缺点:?
第一、如果一个被观察者对象有很多的直接和间接的观察者的话,将所有的观察者都通知到会花费很多时间。?
第二、如果在被观察者之间有循环依赖的话,被观察者会触发它们之间进行循环调用,导致系统崩溃。在使用观察者模式是要特别注意这一点。?
第三、如果对观察者的通知是通过另外的线程进行异步投递的话,系统必须保证投递是以自恰的方式进行的。?
第四、虽然观察者模式可以随时使观察者知道所观察的对象发生了变化,但是观察者模式没有相应的机制使观察者知道所观察的对象是怎么发生变化的。?
观察者模式与其它模式的关系
观察者模式使用了备忘录模式(Memento Pattern)暂时将观察者对象存储在被观察者对象里面。
问答题
第一题、我和妹妹跟妈妈说:“妈妈,我和妹妹在院子里玩;饭做好了叫我们一声。”请问这是什么模式?能否给出类图说明?
问答题答案
第一题答案、这是观察者模式。我和妹妹让妈妈告诉我们饭做好了,这样我们就可以来吃饭了。换用较为技术化的语言来说,当系统的主题(饭)发生变化时,就告诉系统的其它部份(观察者们,也就是妈妈、我和妹妹),使其可以调整内部状态(有开始吃饭的准备),并采取相应的行动(吃饭)。
系统的类图说明如下。

图10、系统的类图。
?
?
转载自:http://www.blogjava.net/supercrsky/articles/202544.html
?