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

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

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

    小偉

    我的java筆記

      BlogJava :: 首頁 :: 新隨筆 :: 聯系 :: 聚合  :: 管理 ::
      29 隨筆 :: 1 文章 :: 23 評論 :: 0 Trackbacks

    深入淺出Java的訪問者模式

    一、引子

      對于系統中一個已經完成的類層次結構,我們已經給它提供了滿足需求的接口。但是面對新增加的需求,我們應該怎么做呢?如果這是為數不多的幾次變動,而且你不用為了一個需求的調整而將整個類層次結構統統地修改一遍,那么直接在原有類層次結構上修改也許是個不錯 的主意。

      但是往往我們遇到的卻是:這樣的需求變動也許會不停的發生;更重要的是需求的任何變動可能都要讓你將整個類層次結構修改個底朝天……。這種類似的操作分布在不同的類里面,不是一個好現象,我們要對這個結構重構一下了。

      那么,訪問者模式也許是你很好的選擇。

      
    二、定義與結構

      訪問者模式,顧名思義使用了這個模式后就可以在不修改已有程序結構的前提下,通過添加額外的“訪問者”來完成對已有代碼功能的提升。

      《設計模式》一書對于訪問者模式給出的定義為:表示一個作用于某對象結構中的各元素的操作。它使你可以在不改變各元素的類的前提下定義作用于這些元素的新操作。從定義可以看出結構對象是使用訪問者模式必須條件,而且這個結構對象必須存在遍歷自身各個對象的方法。這便類似于java中的collection概念了。

      以下是訪問者模式的組成結構:

      1) 訪問者角色(Visitor):為該對象結構中具體元素角色聲明一個訪問操作接口。該操作接口的名字和參數標識了發送訪問請求給具體訪問者的具體元素角色。這樣訪問者就可以通過該元素角色的特定接口直接訪問它。

      2) 具體訪問者角色(Concrete Visitor):實現每個由訪問者角色(Visitor)聲明的操作。

      3) 元素角色(Element):定義一個Accept操作,它以一個訪問者為參數。

      4) 具體元素角色(Concrete Element):實現由元素角色提供的Accept操作。

      5) 對象結構角色(Object Structure):這是使用訪問者模式必備的角色。它要具備以下特征:能枚舉它的元素;可以提供一個高層的接口以允許該訪問者訪問它的元素;可以是一個復合(組合模式)或是一個集合,如一個列表或一個無序集合。

      來張類圖就能更加清晰的看清訪問者模式的結構了。



      那么像引言中假想的。我們應該做些什么才能讓訪問者模式跑起來呢?首先我們要在原有的類層次結構中添加accept方法。然后將這個類層次中的類放到一個對象結構中去。這樣再去創建訪問者角色……

      
    三、舉例

      本人閱歷實在可憐,沒能找到訪問者模式在實際應用中的例子。只好借《Thinking in Patterns with java》中的教學代碼一用。我稍微做了下修改。

    				
    						import java.util.*; 
    import junit.framework.*;

    //
    訪問者角色


    interface Visitor {
     
    void visit(Gladiolus g);
     
    void visit(Runuculus r);
     
    void visit(Chrysanthemum c);
    }

    // The Flower hierarchy cannot be changed:
    //
    元素角色


    interface Flower {
     
    void accept(Visitor v);
    }

    //
    以下三個具體元素角色


    class Gladiolus implements Flower {
     
    public void accept(Visitor v) { v.visit(this);}
    }

    class Runuculus implements Flower {
     
    public void accept(Visitor v) { v.visit(this);}
    }

    class Chrysanthemum implements Flower {
     
    public void accept(Visitor v) { v.visit(this);}
    }

    // Add the ability to produce a string:
    //
    實現的具體訪問者角色


    class StringVal implements Visitor {
     
    String s;
     
    public String toString() { return s; }
     
    public void visit(Gladiolus g) {
      
    s = "Gladiolus";
     
    }

     
    public void visit(Runuculus r) {
      
    s = "Runuculus";
     
    }

     
    public void visit(Chrysanthemum c) {
      
    s = "Chrysanthemum";
     
    }
    }

    // Add the ability to do "Bee" activities:
    //
    另一個具體訪問者角色


    class Bee implements Visitor {
     
    public void visit(Gladiolus g) {
      
    System.out.println("Bee and Gladiolus");
     
    }

     
    public void visit(Runuculus r) {
      
    System.out.println("Bee and Runuculus");
     
    }

     
    public void visit(Chrysanthemum c) {
      
    System.out.println("Bee and Chrysanthemum");
     
    }
    }

    //
    這是一個對象生成器

    //
    這不是一個完整的對象結構,這里僅僅是模擬對象結構中的元素


    class FlowerGenerator {
     
    private static Random rand = new Random();
     
    public static Flower newFlower() {
      
    switch (rand.nextInt(3)) {
      
    default:
       case 0: return new Gladiolus(); 

       
    case 1: return new Runuculus();
       
    case 2: return new Chrysanthemum();
      
    }
     
    }
    }



    //
    客戶 測試程序

    				
    						public class BeeAndFlowers extends TestCase { 

     
    /*
      在這里你能看到訪問者模式執行的流程:

      首先在客戶端先獲得一個具體的訪問者角色

      遍歷對象結構

      對每一個元素調用accept方法,將具體訪問者角色傳入

      這樣就完成了整個過程

     
    */
     //對象結構角色在這里才 組裝 上


     
    List flowers = new ArrayList();
     
    public BeeAndFlowers() {
      
    for(int i = 0; i < 10; i++)
       
    flowers.add(FlowerGenerator.newFlower());
     
    }

     
    Visitor sval ;
     
    public void test() {
      
    // It’s almost as if I had a function to
      
    // produce a Flower string representation:
      //這個地方你可以修改以便使用另外一個具體訪問者角色


      
    sval = new StringVal();
      
    Iterator it = flowers.iterator();
      
    while(it.hasNext()) {
       
    ((Flower)it.next()).accept(sval);
       
    System.out.println(sval);
      
    }
     
    }

     
    public static void main(String args[]) {
      
    junit.textui.TestRunner.run(BeeAndFlowers.class);
     
    }

    }



      四、雙重分派

      對了,你在上面的例子中體會到雙重分派的實現了沒有?

      首先在客戶程序中將具體訪問者模式作為參數傳遞給具體元素角色(加亮的地方所示)。這便完成了一次分派。

      進入具體元素角色后,具體元素角 色調 用作為參數的具體訪問者模式中的visitor方法,同時將自己(this)作為參數傳遞進去。具體訪問者模式再根據參數的不同來選擇方法來執行(加亮的地方所示)。這便完成了第二次分派。

      五、優缺點及適用情況

      先來看下訪問者模式的使用能否避免引言中的痛苦。使用了訪問者模式以后,對于原來的類層次增加新的操作,僅僅需要實現一個具體訪問者角色就可以了,而不必修改整個類層次。而且這樣符合“開閉原則”的要求。而且每個具體的訪問者角色都對應于一個相關操作,因此如果一個操作的需求有變,那么僅僅修改一個具體訪問者角色,而不用改動整個類層次。

      看來訪問者模式確實能夠解決我們面臨的一些問題。

      而且由于訪問者模式為我們的系統多提供了一層“訪問者”,因此我們可以在訪問者中添加一些對元素角色的額外操作。

      但是“開閉原則”的遵循總是片面的。如果系統中的類層次發生了變化,會對訪問者模式產生什么樣的影響呢?你必須修改訪問者角色和每一個具體訪問者角色……

      看來訪問者角色不適合具體元素角色經常發生變化的情況。而且訪問者角色要執行與元素角色相關的操作,就必須讓元素角色將自己內部屬性暴露出來,而在java中就意味著其它的對象也可以訪問。這就破壞了元素角色的封裝性。而且在訪問者模式中,元素與訪問者之間能夠傳遞的信息有限,這往往也會限制訪問者模式的使用。

      《設計模式》一書中給出了訪問者模式適用的情況:

      1) 一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作。

      2) 需要對一個對象結構中的對象進行很多不同的并且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。Visitor使得你可以將相關的操作集中起來定義在一個類中。

      3) 當該對象結構被很多應用共享時,用Visitor模式讓每個應用僅包含需要用到的操作。

      4) 定義對象結構的類很少改變,但經常需要在此結構上定義新的操作。改變對象結構類需要重定義對所有訪問者的接口,這可能需要很大的代價。如果對象結構類經常改變,那么可能還是在這些類中定義這些操作較好。

      你是否能很好的理解呢?

      六、總結

      這是一個巧妙而且復雜的模式,它的使用條件比較苛刻。當系統中存在著固定的數據結構(比如上面的類層次),而有著不同的行為,那么訪問者模式也許是個不錯的選擇?!?/span>

    posted on 2007-02-14 17:50 小偉 閱讀(116) 評論(0)  編輯  收藏

    只有注冊用戶登錄后才能發表評論。


    網站導航:
     
    主站蜘蛛池模板: 亚洲精品无码久久| 亚洲精品亚洲人成在线麻豆| 亚洲国产精品无码久久98| 永久免费在线观看视频| 亚洲综合精品香蕉久久网97| 久久久久国产精品免费免费不卡| 亚洲日产无码中文字幕| 国产免费无码AV片在线观看不卡 | 精品特级一级毛片免费观看| 日本最新免费不卡二区在线| 亚洲av成人中文无码专区| 国产精品免费看久久久无码| 国产成人亚洲精品91专区高清| 亚洲AV网站在线观看| 四虎影视永久在线精品免费| 亚洲精品第一国产综合境外资源| 久久久久女教师免费一区| 亚洲国产精品嫩草影院在线观看| 另类免费视频一区二区在线观看| 久久亚洲精品成人综合| 69天堂人成无码麻豆免费视频| 亚洲精品9999久久久久无码| 免费人成视频在线观看不卡| 在线观看免费视频网站色| 亚洲AV综合色区无码一区| 国产精品爱啪在线线免费观看| 亚洲日韩国产二区无码| 亚洲成av人片一区二区三区| 永久免费AV无码网站国产| 亚洲乱码日产精品BD在线观看| 国产精品四虎在线观看免费| 三级毛片在线免费观看| 亚洲色图综合网站| 国产真人无遮挡作爱免费视频| 韩国免费a级作爱片无码| 亚洲熟妇av一区| 免费又黄又爽又猛的毛片| 国产午夜精品久久久久免费视 | 亚洲avav天堂av在线不卡| 成人免费一区二区无码视频| 一级毛片a免费播放王色电影|