The NoteBook of EricKong

            BlogJava :: 首頁 :: 聯(lián)系 :: 聚合  :: 管理
            611 Posts :: 1 Stories :: 190 Comments :: 0 Trackbacks
          具體元素的接口與實(shí)現(xiàn)類

          public interface Person {
                void accept(Visitor visitor);
          }


          public class Woman implements Person{

              public void accept(Visitor visitor) {
                    visitor.visit(this);
              }
          }


          public class Man implements Person{

              public void accept(Visitor visitor) {
                  visitor.visit(this);
              }
          }



          訪問者接口與實(shí)現(xiàn)類,分別代表男人與女人在不同的狀態(tài)下的表現(xiàn)

          public interface Visitor {
                public void visit(Man man);
                public void visit(Woman girl);
          }

          //成功時Man與Woman的不同表現(xiàn)
          public class Success implements Visitor{

              public void visit(Man man) {
                  System.out.println("當(dāng)男人成功時,背后多半有一個偉大的女人");
              }


              public void visit(Woman woman) {
                  System.out.println("當(dāng)女人成功時,背后大多有一個不成功的男人");
              }
          }

          //戀愛時Man與Woman的不同表現(xiàn)
          public class Love implements Visitor{

              public void visit(Man man) {
                  System.out.println("當(dāng)男人戀愛時,凡事不懂也裝懂");
              }


              public void visit(Woman girl) {
                  System.out.println("當(dāng)女人戀愛時,遇事懂也裝不懂");
              }
          }



          ObjectStructure與客戶端測試代碼

          import java.util.*;

          public class ObjectStructure {
              private List<Person> elements = new ArrayList<Person>();

              public void attach(Person element){
                  elements.add(element);
              }
             
              public void detach(Person element){
                  elements.remove(elements);
              }
             
              //遍歷各種具體元素并執(zhí)行他們的accept方法
              public void display(Visitor visitor){
                  for(Person p:elements){
                      p.accept(visitor);
                  }
              }
          }


          public class Client {
                public static void main(String[] args) {
                  ObjectStructure o = new ObjectStructure();  //依賴于ObjectStructure
                  //實(shí)例化具體元素
                  o.attach(new Man()); 
                  o.attach(new Woman());
                 
                  //當(dāng)成功時不同元素的不同反映
                  Visitor success = new Success();           //依賴于抽象的Visitor接口
                  o.display(success);
                 
                  //當(dāng)戀愛時的不同反映
                  Visitor amativeness = new Love();          //依賴于抽象的Visitor接口
                  o.display(amativeness);
                 
              }
          }



          需求的變化

          假設(shè)現(xiàn)在需求要擴(kuò)展數(shù)據(jù)結(jié)構(gòu),增加一種具體元素,男與女之外的一種不明物體,我們暫時把它稱為“怪獸”,在既有訪問者模式的架構(gòu)下,應(yīng)該怎樣?首先增加一個Bruce類,實(shí)現(xiàn)Person接口。最麻煩的是要修改訪問者接口及其所有具體訪問者!

            因?yàn)閂isit方法中沒有包含訪問Bruce對象的行為,因此我們被迫要去手工更改Visitor(包括抽象的,具體的),在其中添加有關(guān)Bruce對象的行為,這嚴(yán)重違反了“開放-封閉”原則。究其原因在于目前的結(jié)構(gòu)下,被訪問對象與訪問對象互相依賴,自然不利于分離變化,必須去掉一層依賴關(guān)系。

          我們嘗試把Visitor對Person(元素)的依賴關(guān)系去掉,抽象出對應(yīng)每個具體元素的ElementVisitor接口 -->ManVisitor,WomanVisitor,然后把Visitor對Person的依賴關(guān)系轉(zhuǎn)移到ManVisitor與 WomanVisitor身上。
           
          現(xiàn)在Visitor接口已經(jīng)沒有任何抽象方法,只是一個空接口,每一個具體元素對應(yīng)有一個ElementVisitor接口,每一個元素對應(yīng)的ElementVisitor接口有訪問該元素的visit(),相當(dāng)把原來在Visitor接口中聲明工作,交由各個具體ElementVisitor接口完成。


          經(jīng)過改造后的代碼:
          原Visitor接口

          public interface Visitor {
                //退化到?jīng)]有任何抽象方法
          }



          新增加ManVisitor,WomanVisitor接口

          public interface ManVisitor {
                public void visit(Man man);
          }

          public interface WomanVisitor {
                public void visit(Woman w);
          }

           
          具體Visitor實(shí)現(xiàn)類現(xiàn)在同時實(shí)現(xiàn)3個接口

          //由實(shí)現(xiàn)Visitor接口擴(kuò)展成實(shí)現(xiàn)Visitor,WomanVisitor,ManVisitor三個接口
          public class Success implements Visitor,WomanVisitor,ManVisitor{

              public void visit(Man man) {
                  System.out.println("當(dāng)男人成功時,背后多半有一個偉大的女人");
              }

              public void visit(Woman girl) {
                  System.out.println("當(dāng)女人成功時,背后大多有一個不成功的男人");
              }
          }


          //由實(shí)現(xiàn)Visitor接口擴(kuò)展成實(shí)現(xiàn)Visitor,WomanVisitor,ManVisitor三個接口
          public class Love implements Visitor,WomanVisitor,ManVisitor{

              public void visit(Man man) {
                  System.out.println("當(dāng)男人戀愛時,凡事不懂也裝懂");
              }

              public void visit(Woman girl) {
                  System.out.println("當(dāng)女人戀愛時,遇事懂也裝不懂");
              }
          }



          Person接口沒有變化,依舊只依賴于Visitor接口

          public interface Person {
                void accept(Visitor visitor);
          }



          改造后的具體元素類Man與Woman

          public class Man implements Person {

              // 先對visitor進(jìn)行類型轉(zhuǎn)換,再執(zhí)行visit方法,因?yàn)閂isitor接口已經(jīng)沒有聲明任何抽象方法了
              public void accept(Visitor visitor) {
                  if (visitor instanceof ManVisitor) {
                      ManVisitor mv = (ManVisitor) visitor;
                      mv.visit(this);
                  }
              }
          }


          public class Woman implements Person {

              // 先對visitor進(jìn)行類型轉(zhuǎn)換,再執(zhí)行visit方法,因?yàn)閂isitor接口已經(jīng)沒有聲明任何抽象方法了
              public void accept(Visitor visitor) {
                  if (visitor instanceof WomanVisitor) {
                      WomanVisitor wv = (WomanVisitor) visitor;
                      wv.visit(this);
                  }
              }
          }



          ObjectStructure與客戶端測試代碼沒有變化

          import java.util.*;

          public class ObjectStructure {
              private List<Person> elements = new ArrayList<Person>();

              public void attach(Person element){
                  elements.add(element);
              }
             
              public void detach(Person element){
                  elements.remove(elements);
              }
             
              //遍歷各種具體元素并執(zhí)行他們的accept方法
              public void display(Visitor visitor){
                  for(Person p:elements){
                      p.accept(visitor);
                  }
              }
          }


          public class Client {
                public static void main(String[] args) {
                  ObjectStructure o = new ObjectStructure();  //依賴于ObjectStructure
                  //實(shí)例化具體元素
                  o.attach(new Man()); 
                  o.attach(new Woman());
                 
                  //當(dāng)成功時不同元素的不同反映
                  Visitor success = new Success();           //依賴于抽象的Visitor接口
                  o.display(success);
                 
                  //當(dāng)戀愛時的不同反映
                  Visitor amativeness = new Love();          //依賴于抽象的Visitor接口
                  o.display(amativeness);       
              }
          }



          至此改造完畢!我們執(zhí)行客戶端測試代碼,結(jié)果顯示:
          當(dāng)男人成功時,背后多半有一個偉大的女人
          當(dāng)女人成功時,背后大多有一個不成功的男人
          當(dāng)男人戀愛時,凡事不懂也裝懂
          當(dāng)女人戀愛時,遇事懂也裝不懂

          此時,客戶端仍然只依賴于Visitor空接口與ObjectStructure類。可能一開始大家會認(rèn)為空接口沒有什么用,現(xiàn)在就能體現(xiàn)出他的威力了,使客戶端與具體Visitor的高度解耦!也正是這種思維的核心在JavaAPI中也有類似的應(yīng)用,這種空接口被稱為標(biāo)識接口。比如java.io.Serializable與java.rmi.Remote等,標(biāo)識接口里沒有任何方法和屬性,標(biāo)識不對實(shí)現(xiàn)接口不對實(shí)現(xiàn)它的類有任何語義上的要求,它僅僅是表明實(shí)現(xiàn)它的類屬于一種特定的類型。
          上面具體訪問者實(shí)現(xiàn)的多個接口被稱為混合類型。這個概念《Java與模式》中有提及過:當(dāng)一個具體類處于一個類的等級結(jié)構(gòu)之中的時候,為這個具體類定義一個混合類型是可以保證基于這個類型的可插入性的關(guān)鍵。

          =================================無敵分界線====================================

          講了這么長,現(xiàn)在我們測試下改造后的訪問者模式
          首先增加一種行為(狀態(tài)),即原訪問者模式的優(yōu)點(diǎn)

          增加一個具體訪問者Fail,修改一下客戶端測試代碼

          public class Fail implements Visitor,ManVisitor,WomanVisitor{

              public void visit(Man man) {
                  System.out.println("當(dāng)男人失敗時,悶頭喝酒,誰也不用勸");
              }

              public void visit(Woman woman) {
                  System.out.println("當(dāng)女人失敗時,眼淚汪汪,誰也勸不了");
              }
          }



          public class Client {
                public static void main(String[] args) {
                  ObjectStructure o = new ObjectStructure();  //依賴于ObjectStructure
                  //實(shí)例化具體元素
                  o.attach(new Man()); 
                  o.attach(new Woman());
                 
                  //當(dāng)成功時不同元素的不同反映
                  Visitor success = new Success();           //依賴于抽象的Visitor接口
                  o.display(success);
                  System.out.println();
                 
                  //當(dāng)戀愛時的不同反映
                  Visitor amativeness = new Love();          //依賴于抽象的Visitor接口
                  o.display(amativeness);       
                  System.out.println();
                 
                  //新增加失敗時的不同反映
                  Visitor fail = new Fail();
                  o.display(fail);
              }
          }



          結(jié)果顯示:
          當(dāng)男人成功時,背后多半有一個偉大的女人
          當(dāng)女人成功時,背后大多有一個不成功的男人

          當(dāng)男人戀愛時,凡事不懂也裝懂
          當(dāng)女人戀愛時,遇事懂也裝不懂

          當(dāng)男人失敗時,悶頭喝酒,誰也不用勸
          當(dāng)女人失敗時,眼淚汪汪,誰也勸不了



          增加新的行為(狀態(tài))與原來一樣方便!只需要增加一個具體訪問者即可!
          現(xiàn)在我們來增加一個具體元素(正是寫這篇文章的初衷)

          首先增加一個具體元素Bruce

          public class Bruce implements Person{
             
              public void accept(Visitor visitor) {       
                  if(visitor instanceof BruceVisitor){
                      BruceVisitor bv = (BruceVisitor) visitor;
                      bv.visit(this);
                  }
                  //這個else可寫可不寫
                  else{
                      String s = visitor.getClass().getName();
                      String state = s.substring(s.lastIndexOf(".")+1,s.length());
                      System.out.println("噢..原來怪獸在"+state+"的時候是沒有行為的!!");
                  }       
              }
          }


          //按照新的思維方式增加一個對應(yīng)的ElementVisitor接口
          public interface BruceVisitor {
                public void visit(Bruce bruce);
          }



          我們讓Success這個具體訪問者多實(shí)現(xiàn)一個BruceVisitor訪問者接口,和修改一下客戶端代碼進(jìn)行測試

          public class Success implements Visitor,WomanVisitor,ManVisitor,BruceVisitor{

              public void visit(Man man) {
                  System.out.println("當(dāng)男人成功時,背后多半有一個偉大的女人");
              }

              public void visit(Woman girl) {
                  System.out.println("當(dāng)女人成功時,背后大多有一個不成功的男人");
              }

              public void visit(Bruce bruce) {
                  System.out.println("當(dāng)怪獸成功時.........無語..........");
              }
          }


          public class Client {
                public static void main(String[] args) {
                  ObjectStructure o = new ObjectStructure();  //依賴于ObjectStructure

                  o.attach(new Man()); 
                  o.attach(new Woman());
                  o.attach(new Bruce());      //新增一種具體元素Bruce
                 
                  Visitor success = new Success();           //依賴于抽象的Visitor接口
                  o.display(success);
                  System.out.println();
                 
                  Visitor amativeness = new Love();          //依賴于抽象的Visitor接口
                  o.display(amativeness);       
                  System.out.println();
                 
                  Visitor fail = new Fail();
                  o.display(fail);
              }
          }



          顯示結(jié)果:
          當(dāng)男人成功時,背后多半有一個偉大的女人
          當(dāng)女人成功時,背后大多有一個不成功的男人
          當(dāng)怪獸成功時.........無語..........

          當(dāng)男人戀愛時,凡事不懂也裝懂
          當(dāng)女人戀愛時,遇事懂也裝不懂
          噢..原來怪獸在Love的時候是沒有行為的!!

          當(dāng)男人失敗時,悶頭喝酒,誰也不用勸
          當(dāng)女人失敗時,眼淚汪汪,誰也勸不了
          噢..原來怪獸在Fail的時候是沒有行為的!!


          這個結(jié)果你滿意嗎?
          雖然,這只是部分符合“開放-封閉”原則,我們不需要修改Visitor接口,但還是得去修改Success實(shí)現(xiàn)新的接口。但是修改具體類比修改接口的代價小得多,不需要重新編譯所有訪問接口和具體訪問者。使我們面對新的變化也容易得多。而且這還有一個好處,就是可以讓各種元素有選擇地讓別人訪問,如上述例子,這樣使訪問者模式的運(yùn)用起來更加靈活。
          posted on 2010-10-31 17:24 Eric_jiang 閱讀(410) 評論(0)  編輯  收藏 所屬分類: 設(shè)計模式
          主站蜘蛛池模板: 灵武市| 巴塘县| 桂东县| 荔波县| 汝南县| 漳州市| 疏附县| 秭归县| 凯里市| 四子王旗| 南乐县| 乌鲁木齐市| 深水埗区| 汾阳市| 南安市| 泗水县| 炎陵县| 玉环县| 宜宾市| 航空| 民勤县| 吴堡县| 佛冈县| 五指山市| 萍乡市| 左权县| 宽甸| 苗栗县| 湛江市| 靖宇县| 渭南市| 柳河县| 九龙城区| 乐陵市| 平安县| 龙口市| 天水市| 柳河县| 巴彦县| 苍溪县| 安宁市|