我們都知道,蜜蜂是勤勞的精靈,它總是四處采蜜。只要花朵的花瓣一張開,她就飛上去采蜜。我們輕易就能想到,在這里,蜜蜂應該是一個觀察者,而花朵是一個被觀察者。只要花朵發生花瓣張開事件,就通知了觀察者蜜蜂,蜜蜂就可以去采蜜了。
現在我們就來用java程序模擬蜜蜂采蜜。
Java的API為我們設計好了這個模式,我們的被觀察者需要繼承Observable類,而觀察者需要實現Observer接口。
現在我們來看看實際的代碼:
package observer;
import java.util.Observable;
import java.util.Observer;
public class Flower extends Observable
{
public void open() -----------------------------------------------1
{
System.out.println("The flower is opening!"); -----------2
this.setChanged(); ----------------------------------------3
this.notifyObservers(); ---------------------------------------4
}
public void registObserver(Observer observer) -------------------5
{
this.addObserver(observer); --------------------------6
}
public static void main(String[] args)
{
}
}
標號1行定義了一個方法,在這個方法里,主要要做三件事:第一被觀察者的動作,見標號2行的代碼;第二設置被觀察者的狀態變化,如標號3行的代碼;第三通知觀察者,如標號4行的代碼。
package observer;
import java.util.Observable;
import java.util.Observer;
public class Bee implements Observer
{
public void update(Observable arg0, Object arg1)
{
// TODO Auto-generated method stub
System.out.println("It is bee's meat time!");
}
public static void main(String[] args)
{
}
}
觀察者的實現比較簡單,主要就是要實現update方法,在這個方法里實現觀察者在觀察到被觀察者動作后所要做的動作。
下面是測試代碼:
Bee bee = new Bee();
Flower flower = new Flower();
flower.registObserver(bee);
flower.open();
測試結果如下:
The flower is opening!
It is bee's meat time!
現在我們已經基本熟悉了觀察家模式的用法,可以用它來設計我們一些日常所見的現象。如我們常說的一句成語是“螳螂捕蟬,黃雀在后”就可以利用我們的觀察家模式來進行設計。螳螂在四處搜尋著蟬,如果蟬趴在樹枝上一動不動,那么螳螂是很難發現蟬。但如果蟬一有動作,就會被螳螂發現;螳螂一旦發現蟬,就會對蟬發起攻擊;但螳螂萬萬沒有想到,黃雀也在后面搜尋著螳螂,一旦螳螂有所動作,黃雀也會對螳螂發動攻擊。
很明顯,蟬是一個被觀察者,而黃雀是一個觀察者,螳螂則對蟬來說是一個觀察者,對黃雀來說是一個被觀察者,所以螳螂既是觀察者又是被觀察者。
代碼如下:
package observer;
import java.util.Observable;
import java.util.Observer;
public class Cicada extends Observable
{
public void move()
{
System.out.println("The cicada is moving....");
this.setChanged();
this.notifyObservers();
}
public void registObserver(Observer observer)
{
this.addObserver(observer);
}
public static void main(String[] args)
{
}
}
package observer;
import java.util.Observable;
import java.util.Observer;
public class DevilHorse extends Observable implements Observer
{
public void update(Observable arg0, Object arg1)
{
// TODO Auto-generated method stub
System.out.println("It is time for Devil horse to attack....");
this.setChanged();
this.notifyObservers();
}
public void registObserver(Observer observer)
{
this.addObserver(observer);
}
public static void main(String[] args)
{
}
}
package observer;
import java.util.Observable;
import java.util.Observer;
public class YellowBird implements Observer
{
public void update(Observable arg0, Object arg1)
{
// TODO Auto-generated method stub
System.out.println("It is time for a yellow bird to attrack....");
}
public static void main(String[] args)
{
}
}
在上面的代碼中,類DevilHorse既是觀察者,又是被觀察者,所以它既繼承了Observable類,又實現了Observer接口。
下面是測試代碼:
Cicada cicada = new Cicada();
DevilHorse devilHorse = new DevilHorse();
YellowBird yellowBird = new YellowBird();
cicada.registObserver(devilHorse);
devilHorse.registObserver(yellowBird);
cicada.move();
運行結果:
The cicada is moving....
It is time for Devil horse to attack....
It is time for a yellow bird to attrack....
到了上面為止,我們已經把觀察家模式全面的剖析了一遍。現在來對該模式作一些深入的研究。
我們還是以蜜蜂采花為例,現在我們加入鳥兒吃蜂這一個案例。很明顯,我們的Flower類不用變,而Bee類則既是觀察者又是被觀察者,需要做改動為如下代碼:
package observer;
import java.util.Observable;
import java.util.Observer;
public class Bee extends Observable implements Observer
{
public void update(Observable arg0, Object arg1)
{
// TODO Auto-generated method stub
System.out.println("It is bee's meat time!");
this.setChanged();
this.notifyObservers();
}
public void registObserver(Observer observer)
{
this.addObserver(observer);
}
public static void main(String[] args)
{
}
}
而Bird類為:
package observer;
import java.util.Observable;
import java.util.Observer;
public class Bird implements Observer
{
public void update(Observable arg0, Object arg1)
{
// TODO Auto-generated method stub
System.out.println("It is a bird's meat time....");
}
public static void main(String[] args)
{
}
}
測試代碼:
Bee bee = new Bee();
Bird bird = new Bird();
Flower flower = new Flower();
flower.registObserver(bee);
bee.registObserver(bird);
flower.open();
測試結果:
The flower is opening!
It is bee's meat time!
It is a bird's meat time....
我們看看上面的被觀察者類,方法:
public void registObserver(Observer observer)
{
this.addObserver(observer);
}
每次都被原封不動的照抄下來;而在被觀察者的動作方法里頭,總有
this.setChanged();
this.notifyObservers();
這兩句是必須照抄的。
每一個被觀察者都必須這樣,很明顯,這是冗余代碼,我們需要想辦法解決。對于這樣的冗余代碼,我們可以輕松的想到用模板方法模式來解決。
還有,我們來看測試代碼,我們對類的初始化都有很明顯的局限性。如:
Bee bee = new Bee();
Bird bird = new Bird();
Flower flower = new Flower();
flower.registObserver(bee);
我們來看flower和bee的依賴關系,我們都知道依賴顛倒原則說的是要依賴抽象而不要依賴具體實現,而flower和bee的依賴明顯是依賴具體實現bee,不滿足依賴顛倒原則。這帶來的缺點也是顯而易見的:如果有一個蝴蝶類也在觀察著Flower類,那么在運行期才能知道Flower類的觀察者,該怎么辦?
以上的兩個缺點需要我們對觀察家模式作進一步的包裝。
我們首先對被觀察者作包裝,代碼如下:
package observer;
import java.util.Observable;
import java.util.Observer;
public abstract class BaseObservable extends Observable
{
protected void baseDo()
{
observableDo();
this.setChanged();
this.notifyObservers();
}
public void registObserver(Observer observer)
{
this.addObserver(observer);
}
public abstract void observableDo();
}
BaseObservable類是一個模板方法模式的一個直接應用。我們的被觀察者只要繼承了這個類,就只需實現observableDo即可,在該方法里只寫被觀察者的動作,而無須關注其他。
然后是對既是觀察者又是被觀察者的類進行包裝:
package observer;
import java.util.Observable;
import java.util.Observer;
public abstract class BaseObservableObserver extends Observable implements Observer
{
public void update(Observable arg0, Object arg1)
{
// TODO Auto-generated method stub
observableObserverDo(arg0,arg1);
this.setChanged();
this.notifyObservers();
}
public void registObserver(Observer observer)
{
this.addObserver(observer);
}
public abstract void observableObserverDo(Observable arg0, Object arg1);
public static void main(String[] args)
{
}
}
同樣,我們的觀察和被觀察者只要繼承了BaseObservableObserver類,就只要實現observableObserverDo方法即可,在這個方法里頭實現它的動作。
最后是對觀察者的包裝:
package observer;
import java.util.Observable;
import java.util.Observer;
public abstract class BaseObserver implements Observer
{
public void update(Observable arg0, Object arg1)
{
ObserverDo(arg0,arg1);
}
public abstract void ObserverDo(Observable arg0, Object arg1);
public static void main(String[] args)
{
}
}
同樣,觀察者只要繼承了BaseObserver類,就只要在ObserverDo方法里實現觀察家的動作就好了。
下面我們來重新設計Flower、Bee和Bird類:
package observer;
public class Flower extends BaseObservable
{
public void observableDo()
{
System.out.println("The flower is opening...");
}
}
package observer;
import java.util.Observable;
public class Bee extends BaseObservableObserver
{
public void observableObserverDo(Observable arg0, Object arg1)
{
System.out.println("It is a bee's meal time...");
}
}
package observer;
import java.util.Observable;
public class Bird extends BaseObserver
{
public void ObserverDo(Observable arg0, Object arg1)
{
System.out.println("aha,it's a bird's meal time...");
}
}
現在我們可以看到這三個類簡潔了很多,只有和業務相關的動作方法,來看我們的測試類:
BaseObservable flower = new Flower();
BaseObservableObserver bee = new Bee();
BaseObserver bird = new Bird();
flower.registObserver(bee);
bee.registObserver(bird);
flower.baseDo();
測試結果:
The flower is opening...
It is a bee's meal time...
aha,it's a bird's meal time...
我們可以看到,flower和bee的依賴關系也由具體類Bee變成了抽象類BaseObservableObserver。有利于我們的系統擴展。
如,我們增加了一個Butterfly類:
package observer;
import java.util.Observable;
public class Butterfly extends BaseObservableObserver
{
public void observableObserverDo(Observable arg0, Object arg1)
{
System.out.println("The butterfly is coming for a meal...");
}
}
我們的測試端就可以有這樣的代碼:
BaseObservable flower = new Flower();
BaseObservableObserver bee = new Bee();
BaseObservableObserver butterfly = new Butterfly();
BaseObserver bird = new Bird();
ArrayList list = new ArrayList();
list.add(bee);
list.add(butterfly);
for(int i=0;i<list.size();i++)
{
BaseObservableObserver boo = (BaseObservableObserver)list.get(i);
flower.registObserver(boo);
boo.registObserver(bird);
}
flower.baseDo();
這樣使得觀察家模式更加靈活和易于擴展。
測試結果:
The flower is opening...
The butterfly is coming for a meal...
aha,it's a bird's meal time...
It is a bee's meal time...
aha,it's a bird's meal time...
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=547850