隨筆-295  評(píng)論-26  文章-1  trackbacks-0
          java 觀察者模式
          2009-09-10 09:51

          觀察者模式可以參考郵件訂閱的例子

          郵件訂閱設(shè)計(jì)到2個(gè)主要角色,一個(gè)是訂閱者(觀察者),一個(gè)是發(fā)布者

          發(fā)布者可以擁有一個(gè)觀察者的集合,可以添加,刪除觀察者,當(dāng)發(fā)布者發(fā)布一個(gè)新的消息時(shí),要郵件通知觀察者集合中的每一個(gè)。

          所以,發(fā)布者實(shí)現(xiàn)的接口至少應(yīng)具備三個(gè)方法,即注冊(cè)觀察者,注銷觀察者,通知觀察者。

          通知有兩種方式,一種是推(push),一種是拉(pull).

          推,即發(fā)布者通過(guò)調(diào)用觀察者提供的接口,來(lái)告之所有的變動(dòng)(比如新增一個(gè)消息),主動(dòng)推送給觀察者。

          拉,及觀察者可以按需提取所要接受的數(shù)據(jù),而不是全盤(pán)接受,主要體現(xiàn)在程序自己主動(dòng)調(diào)用觀察者的傳值接口,而區(qū)別于推由發(fā)布者來(lái)調(diào)用,此時(shí),需要這個(gè)借口中的參數(shù)包含發(fā)布者對(duì)象,讓程序知道掃描變動(dòng)來(lái)自于哪個(gè)發(fā)布者。

          JDK中內(nèi)置了觀察者模式,位于java.util包中,一個(gè)接口Observer,一個(gè)類Observable,將這兩個(gè)類組合起來(lái)使用,既可以推,又可以拉。

          一個(gè)普通的類,如果繼承了Observable,就成了一個(gè)發(fā)布者,實(shí)現(xiàn)了Observer接口,就成了觀察者。

          JDK中的觀察者模式有一個(gè)弊端,就是發(fā)布者需要繼承一個(gè)類,而不是實(shí)現(xiàn)一個(gè)接口,如果需要成為發(fā)布者的類已經(jīng)集成了一個(gè)類,就不能再繼承Observable了。這時(shí)候,就需要自己來(lái)設(shè)計(jì)一種觀察者模式了。

          JDK 中Swing包中,大量運(yùn)用了觀察者模式,所有的組件都繼承了JComponent,這就是一個(gè)發(fā)布者,它里面包含一個(gè)監(jiān)聽(tīng)器的集合:EventListenerList,用戶可以自定義一個(gè)監(jiān)聽(tīng)器,然后添加到一個(gè)組件中的時(shí)候,該組件就會(huì)把這個(gè)監(jiān)聽(tīng)器注冊(cè)到 EventListenerList中,相當(dāng)于添加了一個(gè)發(fā)布者,當(dāng)用戶對(duì)組件做出反映時(shí),所有的監(jiān)聽(tīng)器(發(fā)布者)都會(huì)收到信息并作出反應(yīng)。

          網(wǎng)上商店中的商品在名稱、價(jià)格發(fā)生變化時(shí),必須自動(dòng)通知會(huì)員,Java的API為我們提供了
             Observer接口和Observable類來(lái)實(shí)現(xiàn)所謂觀察者模式。Observable(可觀察者)類允許在自身發(fā)生改變時(shí),通知其它對(duì)象(實(shí)現(xiàn)接口Observer,觀察者)。


             下面是一個(gè)可觀察者(產(chǎn)品類):
          import java.util.*;
          public class product extends Observable{
             private String name;////產(chǎn)品名
             private float price;////價(jià)格

             public String getName(){ return name;}
             public void setName(String name){
             this.name=name;
             ////設(shè)置變化點(diǎn)
             setChanged();
             notifyObservers(name);////通知觀察者

             }   

             public float getPrice(){ return price;}
             public void setPrice(float price){
             this.price=price;
             ////設(shè)置變化點(diǎn)
             setChanged();
             notifyObservers(new Float(price));

             }

             ////以下可以是數(shù)據(jù)庫(kù)更新 插入命令.
             public void saveToDb(){
             System.out.println("saveToDb");
               }

          }

          下面是兩個(gè)觀察者:
          import java.util.*;
          public class NameObserver implements Observer{

             private String name=null;
             public void update(Observable obj,Object arg){
               if (arg instanceof String){
               name=(String)arg;
               ////產(chǎn)品名稱改變值在name中
               System.out.println("NameObserver :name changet to "+name);

               }

                  }
             }

          import java.util.*;
          public class PriceObserver implements Observer{
             private float price=0;
             public void update(Observable obj,Object arg){
               if (arg instanceof Float){

               price=((Float)arg).floatValue();
            
               System.out.println("PriceObserver :price changet to "+price);

               }


             }

          }
          下面是測(cè)試類:
          public class Test {

             public static void main(String args[]){
                Product product=new Product();
                NameObserver nameobs=new NameObserver();
                PriceObserver priceobs=new PriceObserver();

                ////加入觀察者
                product.addObserver(nameobs);
                product.addObserver(priceobs);

                product.setName("applet");
                product.setPrice(9.22f);

             }
          }
          運(yùn)行結(jié)果:
          C:\java>java    Test
          NameObserver :name changet to applet



          大盤(pán)預(yù)測(cè) 國(guó)富論
          posted on 2009-10-22 10:16 華夢(mèng)行 閱讀(519) 評(píng)論(0)  編輯  收藏

          只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


          網(wǎng)站導(dǎo)航:
           
          主站蜘蛛池模板: 班戈县| 周至县| 通许县| 泗阳县| 钟祥市| 吕梁市| 淮安市| 花垣县| 星座| 陆丰市| 班戈县| 马尔康县| 隆尧县| 河北区| 常熟市| 德清县| 舟山市| 额尔古纳市| 黎城县| 抚松县| 和顺县| 米泉市| 启东市| 黑河市| 囊谦县| 南部县| 漯河市| 邯郸县| 永胜县| 集安市| 荣昌县| 凉城县| 德安县| 留坝县| 环江| 明溪县| 莱芜市| 松潘县| 玛纳斯县| 葵青区| 东乡族自治县|