iNeo

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            30 Posts :: 8 Stories :: 2 Comments :: 0 Trackbacks
             觀察家模式是一個(gè)事件通知模式,被觀察者發(fā)生某個(gè)事件,或者狀態(tài)發(fā)生某個(gè)變化,就通知觀察者,這樣觀察者就能采取適當(dāng)?shù)男袆?dòng)。下面我以一個(gè)簡單的例子來說明一下這個(gè)模式的應(yīng)用。

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

          現(xiàn)在我們就來用java程序模擬蜜蜂采蜜。

          JavaAPI為我們?cè)O(shè)計(jì)好了這個(gè)模式,我們的被觀察者需要繼承Observable類,而觀察者需要實(shí)現(xiàn)Observer接口。

          現(xiàn)在我們來看看實(shí)際的代碼:

          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)

                {

                }

          }

          標(biāo)號(hào)1行定義了一個(gè)方法,在這個(gè)方法里,主要要做三件事:第一被觀察者的動(dòng)作,見標(biāo)號(hào)2行的代碼;第二設(shè)置被觀察者的狀態(tài)變化,如標(biāo)號(hào)3行的代碼;第三通知觀察者,如標(biāo)號(hào)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)

                {

                }

          }

          觀察者的實(shí)現(xiàn)比較簡單,主要就是要實(shí)現(xiàn)update方法,在這個(gè)方法里實(shí)現(xiàn)觀察者在觀察到被觀察者動(dòng)作后所要做的動(dòng)作。

          下面是測(cè)試代碼:

          Bee bee = new Bee();

                         Flower flower = new Flower();

                         flower.registObserver(bee);

                         flower.open();

          測(cè)試結(jié)果如下:

          The flower is opening!

          It is bee's meat time!

          現(xiàn)在我們已經(jīng)基本熟悉了觀察家模式的用法,可以用它來設(shè)計(jì)我們一些日常所見的現(xiàn)象。如我們常說的一句成語是“螳螂捕蟬,黃雀在后”就可以利用我們的觀察家模式來進(jìn)行設(shè)計(jì)。螳螂在四處搜尋著蟬,如果蟬趴在樹枝上一動(dòng)不動(dòng),那么螳螂是很難發(fā)現(xiàn)蟬。但如果蟬一有動(dòng)作,就會(huì)被螳螂發(fā)現(xiàn);螳螂一旦發(fā)現(xiàn)蟬,就會(huì)對(duì)蟬發(fā)起攻擊;但螳螂萬萬沒有想到,黃雀也在后面搜尋著螳螂,一旦螳螂有所動(dòng)作,黃雀也會(huì)對(duì)螳螂發(fā)動(dòng)攻擊。

          很明顯,蟬是一個(gè)被觀察者,而黃雀是一個(gè)觀察者,螳螂則對(duì)蟬來說是一個(gè)觀察者,對(duì)黃雀來說是一個(gè)被觀察者,所以螳螂既是觀察者又是被觀察者。

          代碼如下:

          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類,又實(shí)現(xiàn)了Observer接口。

          下面是測(cè)試代碼:

          Cicada cicada = new Cicada();

                DevilHorse devilHorse = new DevilHorse();

                YellowBird yellowBird = new YellowBird();

                cicada.registObserver(devilHorse);

                devilHorse.registObserver(yellowBird);

                cicada.move();

          運(yùn)行結(jié)果:

          The cicada is moving....

          It is time for Devil horse to attack....

            It is time for a yellow bird to attrack....

          到了上面為止,我們已經(jīng)把觀察家模式全面的剖析了一遍。現(xiàn)在來對(duì)該模式作一些深入的研究。

          我們還是以蜜蜂采花為例,現(xiàn)在我們加入鳥兒吃蜂這一個(gè)案例。很明顯,我們的Flower類不用變,而Bee類則既是觀察者又是被觀察者,需要做改動(dòng)為如下代碼:

          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)

            {

            }

          }

          測(cè)試代碼:

          Bee bee = new Bee();

                Bird bird = new Bird();

                Flower flower = new Flower();

                flower.registObserver(bee);

                bee.registObserver(bird);

                flower.open();

          測(cè)試結(jié)果:

          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);

            }

          每次都被原封不動(dòng)的照抄下來;而在被觀察者的動(dòng)作方法里頭,總有

          this.setChanged();

                this.notifyObservers();

          這兩句是必須照抄的。

          每一個(gè)被觀察者都必須這樣,很明顯,這是冗余代碼,我們需要想辦法解決。對(duì)于這樣的冗余代碼,我們可以輕松的想到用模板方法模式來解決。

          還有,我們來看測(cè)試代碼,我們對(duì)類的初始化都有很明顯的局限性。如:

          Bee bee = new Bee();

                Bird bird = new Bird();

                Flower flower = new Flower();

          flower.registObserver(bee);

          我們來看flowerbee的依賴關(guān)系,我們都知道依賴顛倒原則說的是要依賴抽象而不要依賴具體實(shí)現(xiàn),而flowerbee的依賴明顯是依賴具體實(shí)現(xiàn)bee,不滿足依賴顛倒原則。這帶來的缺點(diǎn)也是顯而易見的:如果有一個(gè)蝴蝶類也在觀察著Flower類,那么在運(yùn)行期才能知道Flower類的觀察者,該怎么辦?

          以上的兩個(gè)缺點(diǎn)需要我們對(duì)觀察家模式作進(jìn)一步的包裝。

          我們首先對(duì)被觀察者作包裝,代碼如下:

          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類是一個(gè)模板方法模式的一個(gè)直接應(yīng)用。我們的被觀察者只要繼承了這個(gè)類,就只需實(shí)現(xiàn)observableDo即可,在該方法里只寫被觀察者的動(dòng)作,而無須關(guān)注其他。

          然后是對(duì)既是觀察者又是被觀察者的類進(jìn)行包裝:

          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類,就只要實(shí)現(xiàn)observableObserverDo方法即可,在這個(gè)方法里頭實(shí)現(xiàn)它的動(dòng)作。

          最后是對(duì)觀察者的包裝:

          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方法里實(shí)現(xiàn)觀察家的動(dòng)作就好了。

          下面我們來重新設(shè)計(jì)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...");

            }

          }

          現(xiàn)在我們可以看到這三個(gè)類簡潔了很多,只有和業(yè)務(wù)相關(guān)的動(dòng)作方法,來看我們的測(cè)試類:

          BaseObservable flower = new Flower();

                BaseObservableObserver bee = new Bee();

                BaseObserver bird = new Bird();

                flower.registObserver(bee);

                bee.registObserver(bird);

                flower.baseDo();

          測(cè)試結(jié)果:

          The flower is opening...

          It is a bee's meal time...

            aha,it's a bird's meal time...

          我們可以看到,flowerbee的依賴關(guān)系也由具體類Bee變成了抽象類BaseObservableObserver。有利于我們的系統(tǒng)擴(kuò)展。

          如,我們?cè)黾恿艘粋€(gè)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...");

            }

          }

          我們的測(cè)試端就可以有這樣的代碼:

          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();

          這樣使得觀察家模式更加靈活和易于擴(kuò)展。

          測(cè)試結(jié)果:

          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 只牽這只狗 閱讀(335) 評(píng)論(0)  編輯  收藏 所屬分類: Java
          主站蜘蛛池模板: 南郑县| 寿阳县| 芦山县| 四会市| 清流县| 北京市| 永修县| 临沂市| 富阳市| 九江市| 馆陶县| 阿勒泰市| 尼木县| 五华县| 德州市| 克拉玛依市| 桦川县| 白沙| 东山县| 雷山县| 高安市| 蒲城县| 通榆县| 陕西省| 平远县| 元阳县| 延庆县| 冷水江市| 新和县| 镇远县| 油尖旺区| 安平县| 鸡泽县| 民丰县| 新和县| 泸溪县| 汪清县| 合阳县| 福州市| 塘沽区| 德阳市|