按照“四人團(tuán)”的說(shuō)法,Observer模式的意圖是“定義對(duì)象間的一種一對(duì)多的依賴關(guān)系,當(dāng)一個(gè)對(duì)象的狀態(tài)發(fā)生改變時(shí),所有依賴于它的對(duì)象都得到通知并被自動(dòng)更新”。
問(wèn)題:當(dāng)某個(gè)事件發(fā)生時(shí),你需要向一系列對(duì)象發(fā)出通知,而這個(gè)對(duì)象的列表是不斷變化的。(而當(dāng)依賴關(guān)系固定或幾乎固定時(shí),加入Observer模式只會(huì)增加復(fù)雜性)
簡(jiǎn)單來(lái)說(shuō),Observer模式讓一個(gè)對(duì)象(觀察者,Observer)去監(jiān)視另一個(gè)對(duì)象(目標(biāo),Subject);它使得目標(biāo)和觀察者之間建立一種 "發(fā)布--訂閱"(publish-subscribe )的關(guān)系。通過(guò)Observer模式,觀察者可以向目標(biāo)登記,表明自己要從目標(biāo)接收事件。目標(biāo)需要向觀察者通知事件時(shí),只是簡(jiǎn)單地將事件發(fā)給每一個(gè)觀察者。
例如,有一個(gè)基于某種數(shù)據(jù)模型的電子表格。只要數(shù)據(jù)模型發(fā)生變化,電子表格就需要更新表格單元以及內(nèi)嵌的圖表。這個(gè)例子中,目標(biāo)是數(shù)據(jù)模型,觀察者是表格單元和圖表。當(dāng)觀察者接收到數(shù)據(jù)模型已經(jīng)變化的通知時(shí),它們就更新自己。
Observer模式的好處是:它解除了觀察者和目標(biāo)之間的耦合關(guān)系。目標(biāo)不需要知道它的觀察者的任何信息。相反,目標(biāo)只是允許觀察者訂閱事件。當(dāng)目標(biāo)產(chǎn)生一個(gè)事件時(shí),它簡(jiǎn)單地將事件傳給每一個(gè)觀察者。
看看下面的Java示例:
public interface Subject {
public void addObserver( Observer o );
public void removeObserver( Observer o );
}
上面的代碼中,Subject接口定義了兩個(gè)方法(method),每個(gè)Subject都必須實(shí)現(xiàn)它們,以使Observer可以在Subject中增加或刪除自身。
public interface Observer {
public void update( Subject o );
}
Observer接口(如上)列出了一個(gè)方法(method),每個(gè)Observer都必須實(shí)現(xiàn)它,以使Subject可以發(fā)送更新消息給Observer。
下面看看Subject的一個(gè)簡(jiǎn)單的實(shí)現(xiàn)--IntegerDataBag:
import java.util.ArrayList;
import java.util.Iterator;
public class IntegerDataBag implements Subject {
private ArrayList list = new ArrayList();
private ArrayList observers = new ArrayList();
public void add( Integer i ) {
list.add( i );
notifyObservers();
}
public Iterator iterator() {
return list.iterator();
}
public Integer remove( int index ) {
if( index < list.size() ) {
Integer i = (Integer) list.remove( index );
notifyObservers();
return i;
}
return null;
}
public void addObserver( Observer o ) {
observers.add( o );
}
public void removeObserver( Observer o ) {
observers.remove( o );
}
private void notifyObservers() {
// loop through and notify each observer
Iterator i = observers.iterator();
while( i.hasNext() ) {
Observer o = ( Observer ) i.next();
o.update( this );
}
}
}
IntegerDataBag適用于使用Integer的場(chǎng)合。IntegerDataBag也允許Observer增加和刪除它們自身。
再看看兩個(gè)Observer的實(shí)現(xiàn)--IntegerAdder和IntegerPrinter:
import java.util.Iterator;
public class IntegerAdder implements Observer {
private IntegerDataBag bag;
public IntegerAdder( IntegerDataBag bag ) {
this.bag = bag;
bag.addObserver( this );
}
public void update( Subject o ) {
if( o == bag ) {
System.out.println( "The contents of the IntegerDataBag have changed." );
int counter = 0;
Iterator i = bag.iterator();
while( i.hasNext() ) {
Integer integer = ( Integer ) i.next();
counter+=integer.intValue();
}
System.out.println( "The new sum of the integers is: " + counter );
}
}
}
import java.util.Iterator;
public class IntegerPrinter implements Observer {
private IntegerDataBag bag;
public IntegerPrinter( IntegerDataBag bag ) {
this.bag = bag;
bag.addObserver( this );
}
public void update( Subject o ) {
if( o == bag ) {
System.out.println( "The contents of the IntegerDataBag have changed." );
System.out.println( "The new contents of the IntegerDataBag contains:" );
Iterator i = bag.iterator();
while( i.hasNext() ) {
System.out.println( i.next() );
}
}
}
}
IntegerAdder和IntegerPrinter將自己作為觀察者增加到IntegerDataBag。當(dāng)IntegerAdder接收到一條更新消息時(shí),它先統(tǒng)計(jì)bag中的總數(shù),然后顯示結(jié)果。同樣,當(dāng)IntegerPrinter接收到一條更新消息時(shí),它打印出bag中的Interger。
下面是一個(gè)簡(jiǎn)單的main(),它使用了上面的幾個(gè)類(lèi):
public class Driver {
public static void main( String [] args ) {
Integer i1 = new Integer( 1 ); Integer i2 = new Integer( 2 );
Integer i3 = new Integer( 3 ); Integer i4 = new Integer( 4 );
Integer i5 = new Integer( 5 ); Integer i6 = new Integer( 6 );
Integer i7 = new Integer( 7 ); Integer i8 = new Integer( 8 );
Integer i9 = new Integer( 9 );
IntegerDataBag bag = new IntegerDataBag();
bag.add( i1 ); bag.add( i2 ); bag.add( i3 ); bag.add( i4 );
bag.add( i5 ); bag.add( i6 ); bag.add( i7 ); bag.add( i8 );
IntegerAdder adder = new IntegerAdder( bag );
IntegerPrinter printer = new IntegerPrinter( bag );
// adder and printer add themselves to the bag
System.out.println( "About to add another integer to the bag:" );
bag.add( i9 );
System.out.println("");
System.out.println("About to remove an integer from the bag:");
bag.remove( 0 );
}
}
運(yùn)行main,你將看到:
c:\javaworld\java Driver
About to add another integer to the bag:
The contents of the IntegerDataBag have changed.
The new sum of the intergers is: 45
The contents of the IntegerDataBag have changed.
The new contents of the IntegerDataBag contains:
1
2
3
4
5
6
7
8
9
About to remove an integer from the bag:
The contents of the IntegerDataBag have changed.
The new sum of the intergers is: 44
The contents of the IntegerDataBag have changed.
The new contents of the IntegerDataBag contains:
2
3
4
5
6
7
8
9
IntegerDataBag/IntegerAdder/IntegerPrinter是應(yīng)用Observer模式的一個(gè)很簡(jiǎn)單的例子。Java本身有大量使用Observer模式的例子:AWT/Swing事件模型,還有java.util.Observer和java.util.Observable接口等,都是很好的例子