iNeo

            BlogJava :: 首頁 :: 聯系 :: 聚合  :: 管理
            30 Posts :: 8 Stories :: 2 Comments :: 0 Trackbacks
             觀察家模式是一個事件通知模式,被觀察者發生某個事件,或者狀態發生某個變化,就通知觀察者,這樣觀察者就能采取適當的行動。下面我以一個簡單的例子來說明一下這個模式的應用。

          我們都知道,蜜蜂是勤勞的精靈,它總是四處采蜜。只要花朵的花瓣一張開,她就飛上去采蜜。我們輕易就能想到,在這里,蜜蜂應該是一個觀察者,而花朵是一個被觀察者。只要花朵發生花瓣張開事件,就通知了觀察者蜜蜂,蜜蜂就可以去采蜜了。

          現在我們就來用java程序模擬蜜蜂采蜜。

          JavaAPI為我們設計好了這個模式,我們的被觀察者需要繼承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);

          我們來看flowerbee的依賴關系,我們都知道依賴顛倒原則說的是要依賴抽象而不要依賴具體實現,而flowerbee的依賴明顯是依賴具體實現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方法里實現觀察家的動作就好了。

          下面我們來重新設計FlowerBeeBird類:

          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...

          我們可以看到,flowerbee的依賴關系也由具體類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

          posted on 2005-12-09 16:26 只牽這只狗 閱讀(338) 評論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 大渡口区| 乐山市| 讷河市| 丹东市| 根河市| 依安县| 陇南市| 衡水市| 洛南县| 工布江达县| 中宁县| 永德县| 祁阳县| 邛崃市| 来凤县| 锡林浩特市| 开原市| 城固县| 怀远县| 白朗县| 桦甸市| 孝昌县| 建阳市| 洛扎县| 平顺县| 鹤岗市| 沁阳市| 商洛市| 伊宁市| 柏乡县| 敖汉旗| 闵行区| 横峰县| 江达县| 罗平县| 恩平市| 祁阳县| 孙吴县| 临西县| 康定县| 宁德市|