<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    DANCE WITH JAVA

    開(kāi)發(fā)出高質(zhì)量的系統(tǒng)

    常用鏈接

    統(tǒng)計(jì)

    積分與排名

    好友之家

    最新評(píng)論

    訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén)

    訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén)
    本文對(duì)應(yīng)代碼下載這里
    一,問(wèn)題提出
    訪問(wèn)同一類(lèi)型的集合類(lèi)是我們最常見(jiàn)的事情了,我們工作中這樣的代碼太常見(jiàn)了。

    1 Iterator ie  =  list.iterator();
    2 while (ie.hasNext()) {
    3     Person p  =  (Person)ie.next();
    4     p.doWork();
    5 }


    這種訪問(wèn)的特點(diǎn)是集合類(lèi)中的對(duì)象是同一類(lèi)對(duì)象Person,他們擁有功能的方法run,我們調(diào)用的恰好是這個(gè)共同的方法。
    在大部份的情況下,這個(gè)是可以的,但在一些復(fù)雜的情況,如被訪問(wèn)者的繼承結(jié)構(gòu)復(fù)雜,被訪問(wèn)者的并不是同一類(lèi)對(duì)象,
    也就是說(shuō)不是繼承自同一個(gè)根類(lèi)。方法名也并不相同。例如Java GUI中的事件就是一個(gè)例子。
    例如這樣的問(wèn)題,有如下類(lèi)和方法:
    類(lèi):PA ,方法:runPA();
    類(lèi):PB ,方法:runPB();
    類(lèi):PC ,方法:runPC();
    類(lèi):PD ,方法:runPD();
    類(lèi):PE ,方法:runPE();
    有一個(gè)集合類(lèi)List
    List list = new ArrayList();
    list.add(new PA());
    list.add(new PB());
    list.add(new PC());
    list.add(new PD());
    list.add(new PE());
    ....
    二:解決
    要求能訪問(wèn)到每個(gè)類(lèi)的對(duì)應(yīng)的方法。我們第一反應(yīng)應(yīng)該是這樣的。

     1 Iterator ie  =  list.iterator();
     2 while (ie.hasNext()) {
     3     Object obj  =  ie.next();
     4      if  (obj  instanceof  PA) {
     5         ((PA)obj).runPA();
     6     }
    else   if (obj  instanceof  PB) {
     7         ((PB)obj).runPB();
     8     }
    else   if (obj  instanceof  PC) {
     9         ((PC)obj).runPC();
    10     }
    else   if (obj  instanceof  PD) {
    11         ((PD)obj).runPD();
    12     }
    else   if (obj  instanceof  PE) {
    13         ((PE)obj).runPE();
    14     }

    15 }


    三:新問(wèn)題及分析解決
    當(dāng)數(shù)目變多的時(shí)候,維護(hù)if else是個(gè)費(fèi)力氣的事情:
    仔細(xì)分析if,else做的工作,首先判斷類(lèi)型,然後根據(jù)類(lèi)型執(zhí)行相應(yīng)的函數(shù)
    如何才能解決這兩個(gè)問(wèn)題呢?首先想到的是java的多態(tài),多態(tài)就是根據(jù)參數(shù)執(zhí)行相應(yīng)的內(nèi)容,
    能很容易的解決第二個(gè)問(wèn)題,我們可以寫(xiě)這樣一個(gè)類(lèi):

     1 public   class  visitor {
     2      public   void  run(PA pa) {
     3         pa.runPA();
     4     }

     5      public   void  run(PB pb) {
     6         pb.runPB();
     7     }

     8      public   void  run(PC pc) {
     9         pc.runPC();
    10     }

    11      public   void  run(PD pd) {
    12         pd.runPD();
    13     }

    14      public   void  run(PE pe) {
    15         pe.runPE();
    16     }

    17 }


    這樣只要調(diào)用run方法,傳入對(duì)應(yīng)的參數(shù)就能執(zhí)行了。
    還有一個(gè)問(wèn)題就是判斷類(lèi)型。由于重載(overloading)是靜態(tài)多分配(java語(yǔ)言本身是支持"靜態(tài)多分配"的。
    關(guān)于這個(gè)概念請(qǐng)看這里)所以造成重載只根據(jù)傳入對(duì)象的定義類(lèi)型,而不是實(shí)際的類(lèi)型,所以必須在傳入前就確定類(lèi)型,
    這可是個(gè)難的問(wèn)題,因?yàn)樵谌萜髦袑?duì)象全是Object,出來(lái)后要是判斷是什么類(lèi)型必須用
    if (xx instanceof xxx)這種方法,如果用這種方法啟不是又回到了原點(diǎn),有沒(méi)有什么更好的辦法呢?

    我們知到Java還有另外一個(gè)特點(diǎn),覆寫(xiě)(overriding),而覆寫(xiě)是"動(dòng)態(tài)單分配"的(關(guān)于這個(gè)概念見(jiàn)這里),
    那如何利用這個(gè)來(lái)實(shí)現(xiàn)呢?看下邊這個(gè)方法:
     我們讓上邊的一些類(lèi)PA PB PC PD PE都實(shí)現(xiàn)一個(gè)接口P,加入一個(gè)方法,accept();

     1 public   void  accept(visitor v) {
     2      // 把自己傳入1
     3     v.run( this );
     4 }

     5 然後在visitor中加入一個(gè)方法
     6 public   void  run(P p) {
     7      // 把自己傳入2
     8     p.accept( this );
     9 }

    10 // 這樣你在遍歷中可以這樣寫(xiě)
    11 Visitor v  =   new  Visitor();
    12 Iterator ie  =  list.iterator();
    13 while (ie.hasNext()) {
    14     P p  =  (P)ie.next();
    15         p.accept(v);
    16     }

    17 }


    首先執(zhí)行的是"把自己傳入2",在這里由于Java的特性,實(shí)際執(zhí)行的是子類(lèi)的accept(),也就是實(shí)際類(lèi)的accept
    然後是"把自己傳入1",在這里再次把this傳入,就明確類(lèi)型,ok我們巧妙的利用overriding解決了這個(gè)問(wèn)題
    其實(shí)歸納一下第二部分,一個(gè)關(guān)鍵點(diǎn)是"自己認(rèn)識(shí)自己",是不是很可笑。
    其實(shí)在計(jì)算計(jì)技術(shù)領(lǐng)域的很多技術(shù)上看起來(lái)很高深的東西,其實(shí)就是現(xiàn)有社會(huì)中人的生活方式的一種映射
    而且這種方式是簡(jiǎn)單的不能再簡(jiǎn)單的方式。上邊的全部過(guò)程基本上是一個(gè)簡(jiǎn)單的visitor模式實(shí)現(xiàn),visitor模式
    已經(jīng)是設(shè)計(jì)模式中比較復(fù)雜的模式了,但其實(shí)原理簡(jiǎn)單到你想笑。看看下邊這個(gè)比喻也許你的理解會(huì)更深刻。

    四:一個(gè)幫助理解的比喻:
    題目:指揮工人工作
    條件:你有10個(gè)全能工人,10樣相同工作。
    需求:做完工作
    實(shí)現(xiàn):大喊一聲所有人去工作

    條件變了,工人不是全能,但是工作相同,ok問(wèn)題不大
    條件再變,工作不是相同,但工人是全能,ok問(wèn)題不大

    以上三種情況在現(xiàn)實(shí)生活中是很少發(fā)生得,最多的情況是這樣:
    10個(gè)工人,每人會(huì)做一種工作,10樣工作。你又一份名單Collection)寫(xiě)著誰(shuí)做什么。但你不認(rèn)識(shí)任何人
    這個(gè)時(shí)候你怎么指揮呢,方案一:
    你可以一個(gè)個(gè)的叫工人,然後問(wèn)他們名字,認(rèn)識(shí)他們,查名單,告訴他們做什么工作。
    你可以直接叫出他們名字,告訴他們干什么,不需要知到他是誰(shuí)。
    看起來(lái)很簡(jiǎn)單。但如果你要指揮10萬(wàn)人呢 ?而且人員是流動(dòng)的,每天的人不同,你每天拿到一張文檔。
    其實(shí)很簡(jiǎn)單,最常用的做法是,你把這份名單貼在墻上,然後大喊一聲,所有人按照去看,按照自己的分配情況去做。
    這里利用的關(guān)鍵點(diǎn)是"所有工人自己認(rèn)識(shí)自己",你不能苛求每個(gè)工人會(huì)做所有工作,不能苛求所有工作相同,但你
    能要求所有工人都認(rèn)識(shí)自己。

    再想想我們開(kāi)始的程序,每個(gè)工人對(duì)應(yīng)著PA PB PC PD PE....
    所有的工人都使工人P
    每個(gè)工人會(huì)做的東西不一樣runPA runPB runPC
    你有一份名單Visitor(重載)記錄著誰(shuí)做什么工作。

    看完上邊這些,你是不是會(huì)產(chǎn)生如下的問(wèn)題:
    問(wèn)題:為什么不把這些方法的方法名做成一樣的,那就可以解決了。
    例如,我們每個(gè)PA ,PB ,PC都加入一個(gè)run 方法,然後run內(nèi)部再調(diào)用自己對(duì)應(yīng)的runPx()方法。
    答案:有些時(shí)候從不同的角度考慮,或者因?yàn)閷?shí)現(xiàn)的復(fù)雜度早成很難統(tǒng)一方法名。
    例如上邊指揮人工作的例子的例子,其實(shí)run方法就是大叫一聲去工作,因?yàn)槊總€(gè)工人只會(huì)做一種工作,所以能行
    但我們不能要求所有人只能會(huì)做一種事情,這個(gè)要求很愚蠢。所以如果每個(gè)工人會(huì)干兩種或者多種工作呢,
    也就是我PA 有runPA() walkPA()等等方法, PB有runPB() climbPB()等等。。。
    這個(gè)時(shí)候按照名單做事才是最好的辦法。

    五:作者的話(huà)
    所以說(shuō)模式中很多復(fù)雜的東西,在現(xiàn)實(shí)中其實(shí)是很基本的東西,多多代入代出能幫助理解模式。

    看完本文,如果你對(duì)visitor模式有更多的興趣,想了解更多請(qǐng)看如下幾篇文章。
    1,靜態(tài)分派,動(dòng)態(tài)分派,多分派,單分派 --------------   visitor模式準(zhǔn)備
    2,訪問(wèn)差異類(lèi)型的集合類(lèi) ------------------------   visitor模式入門(mén)(本文)
    3,visitor模式理論及學(xué)術(shù)概念-------------------   visitor模式深入
    4,重載overloading和覆寫(xiě)overriding哪個(gè)更早執(zhí)行--   visitor幫助篇
    雖然排列順序是1,2,3,4 但是我個(gè)人建議的學(xué)習(xí)方式是2,1,3,4因?yàn)檫@個(gè)順序更方便一般人理解

     

     

     

     

     

     

     

     

     

     


     

    posted on 2006-12-18 20:18 dreamstone 閱讀(4993) 評(píng)論(14)  編輯  收藏 所屬分類(lèi): 設(shè)計(jì)模式

    評(píng)論

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-19 09:37 hannyu

    我有一個(gè)疑問(wèn),下面這段代碼是不是少寫(xiě)了什么東西?我怎么覺(jué)得p.accept與v.run之間是死循環(huán)呢?請(qǐng)解釋一下
    1 public void accept(visitor v) {
    2 // 把自己傳入1
    3 v.run( this );
    4 }
    5 然後在visitor中加入一個(gè)方法
    6 public void run(P p) {
    7 // 把自己傳入2
    8 p.accept( this );
    9 }
    10 // 這樣你在遍歷中可以這樣寫(xiě)
    11 Visitor v = new Visitor();
    12 Iterator ie = list.iterator();
    13 while (ie.hasNext()) {
    14 P p = (P)ie.next();
    15 p.accept(v);
    16 }
    17 }   回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-19 09:46 themax

    首先執(zhí)行的是"把自己傳入2",???
    應(yīng)該是"把自己傳入1"吧.

      回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-19 21:53 dreamstone

    to hannyu :
    其實(shí)這就是visitor模式關(guān)鍵的地方,p.accept(v)的時(shí)候會(huì)發(fā)生向下轉(zhuǎn)型,所以執(zhí)行的是子類(lèi)的accept()方法,而子類(lèi)的accept()方法中,傳入this就是子類(lèi)而不是父類(lèi)了。也就是說(shuō)PA中調(diào)用v.run(this)其實(shí)傳入的this是PA類(lèi)型,而不是P類(lèi)型了,這樣visitor重載的時(shí)候就會(huì)執(zhí)行run(Pa pa)而不是run(P p),所以不會(huì)死循環(huán)的。代碼在公司,明天把代碼上傳,你執(zhí)行一下就知道了。
    (上邊就是說(shuō)的自己認(rèn)識(shí)自己了)  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-19 21:56 dreamstone

    to themax :
    可能我寫(xiě)的有點(diǎn)歧意,我上邊的“把自己傳入2";是個(gè)label,相當(dāng)于姓名一,姓名二,下邊解釋的是拿它來(lái)當(dāng)label用,而不是把自己傳入給第二個(gè),sorry。  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-19 22:31 dreamstone

    另外,加入了source的下載,見(jiàn)文章開(kāi)始,雖然簡(jiǎn)單,但是可以看看。
    個(gè)人感覺(jué)visitor模式是模式中比較復(fù)雜的。實(shí)現(xiàn)起來(lái)也是比較巧的.兩次this的利用。好像有一種學(xué)術(shù)的叫法"返還球"  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-20 09:22 hannyu

    多謝,看了源代碼終于明白了,visitor模式繞來(lái)繞去的真難理解。接口P應(yīng)該只起來(lái)一個(gè)輔助作用,如果有個(gè)特殊點(diǎn)的命名就容易理解一些了。比如visitee?  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-27 13:07 jounyc

    我覺(jué)得把Visitor中

    public void run(Person p)
    {
    p.accept(this);
    }

    去掉也可以運(yùn)行,
    因?yàn)樵?p.accept(v); 時(shí)父類(lèi)向下轉(zhuǎn)型,執(zhí)行子類(lèi)的accept(Visitor v),
    然后就執(zhí)行子類(lèi)在Visitor中對(duì)應(yīng)的run()了,和上面那段沒(méi)有關(guān)系阿。

    樓主出來(lái)解釋下。  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2006-12-27 19:52 dreamstone[匿名]

    呵呵,其實(shí)我當(dāng)時(shí)寫(xiě)這個(gè)是為了這樣的情況,可能這種情況用的更多
    Visitor v = new Visitor();
    Iterator ie = list.iterator();
    while (ie.hasNext()) {
    P p = (P)ie.next();
    v.run(p);
    }
    這個(gè)時(shí)候那個(gè)函數(shù)就必須有了。因?yàn)閞un(p)的時(shí)候必須在編譯器有一個(gè)對(duì)應(yīng)的函數(shù),這兩個(gè)的區(qū)別是看想問(wèn)題的角度了。
    是讓visitor 訪問(wèn)每一個(gè)p
    還是讓每一個(gè)P運(yùn)行。
    不過(guò)更多情況應(yīng)該是v.run(p);更復(fù)合思考的習(xí)慣。后來(lái)發(fā)文的時(shí)候簡(jiǎn)化了一下。


      回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén)[未登錄](méi) 2007-02-09 11:52 xmlspy

    代碼中

    for(int i=0;i<list.size();i++){
    P p = (P)list.get(i);
    p.accept(v);
    }

    這種方式嚴(yán)重影響性能!!

    改成:

    P p =null;
    for(int i=0;i<list.size();i++){
    p = (P)list.get(i);
    p.accept(v);
    }
      回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2007-02-28 12:17 dreamstone

    to xmlspy:
    建議回文的時(shí)候調(diào)查一下,你的說(shuō)法是很錯(cuò)誤的:具體說(shuō)明見(jiàn)這里
    http://m.tkk7.com/dreamstone/archive/2007/02/11/99207.aspx  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2007-07-05 10:32 xnabx

    通過(guò)抽象類(lèi)可以非常方便的實(shí)現(xiàn),也就是“自己找自己”

    //抽象類(lèi) P
    public abstract class P{
    public abstract String run();
    }

    //類(lèi)PA繼承抽象類(lèi)P
    public class PA entends P{
    public String run(){
    return "PB";
    }
    }
    //類(lèi)PB繼承抽象類(lèi)P
    public class PB entends P{
    public String run(){
    return "PB";
    }
    }
    //類(lèi)PC繼承抽象類(lèi)P
    public class PC entends P{
    public String run(){
    return "PC";
    }
    }
    //類(lèi)PD繼承抽象類(lèi)P
    public class PD entends P{
    public String run(){
    return "PD";
    }
    }
    //類(lèi)PE繼承抽象類(lèi)P
    public class PE entends P{
    public String run(){
    return "PE";
    }
    }


    List list = new ArrayList();
    list.add(new PA());
    list.add(new PB());
    list.add(new PC());
    list.add(new PD());
    list.add(new PE());


    Iterator ie = list.iterator();
    while (ie.hasNext()) {
    Run p = (Run)ie.next();
    p.run();
    }   回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2007-07-05 11:21 xnabx

    Iterator ie = list.iterator();
    while (ie.hasNext()) {
    Run p = (Run)ie.next();
    p.run();
    } 應(yīng)該是

    Iterator ie = list.iterator();
    while (ie.hasNext()) {
    P p = (P)ie.next();
    p.run();
    }   回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2007-07-06 12:58 dreamstone

    @xnabx
    你根本不理解什么是visitor啊。
    你的那種實(shí)現(xiàn)方式是:
    調(diào)用一個(gè)集合類(lèi)中,不同的對(duì)像的"同一個(gè)"方法。
    我的實(shí)現(xiàn)是:
    調(diào)用一個(gè)集合類(lèi)中,不同的對(duì)象的"不同的"方法

    另外你曲解了demo的含義,我并不是未了打印出pa,pb,pc,pd只是為了直觀那么些。這有點(diǎn)像我問(wèn)到美國(guó)怎么走,你告訴我做300能上三環(huán)

    至于為什么需要這種需求,最開(kāi)始寫(xiě)了個(gè)簡(jiǎn)單的引入,如果你開(kāi)發(fā)過(guò)很復(fù)雜的系統(tǒng)你就會(huì)明白這種需求是經(jīng)常存在的,特別是你在改造一個(gè)有很多已有模塊的工程。  回復(fù)  更多評(píng)論   

    # re: 訪問(wèn)差異類(lèi)型的集合類(lèi)--visitor模式入門(mén) 2010-01-03 17:02 事實(shí)上

    解釋的太牽強(qiáng)了,誤人子弟  回復(fù)  更多評(píng)論   

    主站蜘蛛池模板: 四虎国产精品永久免费网址| 成年大片免费高清在线看黄| 最近中文字幕mv免费高清在线| 亚洲人成亚洲人成在线观看| 一个人看的hd免费视频| 亚洲人成网站18禁止一区| 老司机午夜在线视频免费观| 日韩精品亚洲专区在线观看| 免费人妻精品一区二区三区| 亚洲国产香蕉人人爽成AV片久久| 欧亚一级毛片免费看| 亚洲一区二区三区无码影院| 免费无码又爽又刺激网站直播 | 国产精品亚洲五月天高清| 日本xxwwxxww在线视频免费| 青草青草视频2免费观看| 国产亚洲精品a在线观看| 十八禁视频在线观看免费无码无遮挡骂过| 亚洲V无码一区二区三区四区观看| 99久热只有精品视频免费观看17| 亚洲国产电影在线观看| 好爽又高潮了毛片免费下载| 色多多www视频在线观看免费| 亚洲精品午夜无码专区| 曰批视频免费40分钟试看天天 | 美女被免费网站视频在线| 国产精品亚洲精品日韩已方| 国产成人免费ā片在线观看老同学| 亚洲毛片免费观看| 国产成人3p视频免费观看| a毛片视频免费观看影院| 亚洲国产美女在线观看 | 亚洲AV午夜成人影院老师机影院| 无码国产精品一区二区免费| 国产一区二区三区亚洲综合| 亚洲精品二区国产综合野狼| 毛色毛片免费观看| 免费精品99久久国产综合精品| 中文字幕无码亚洲欧洲日韩| 久久伊人亚洲AV无码网站| 美女裸身网站免费看免费网站|