Java設計模式之從[魔獸世界包裹系統]分析組合(Composite)模式

來源:互聯網
上載者:User

  RPG遊戲中的包裹(或者稱為背包)是玩家攜帶物品的地方,它的大小決定著玩家能夠攜帶物品數量。如在魔獸世界中,玩家起初的物品欄(將物品欄視為玩家的唯一一個包裹)的格子很少,但是玩家可以將新的包裹放在物品欄中,達到擴充物品欄的效果。也就是說,物品欄可以放消耗品、武器等零散的物品,當然也可以放包裹。

  假定魔獸世界有如下設定:玩家一開始擁有一個預設的包裹(物品欄),玩家可以獲得新的包裹放在物品欄上。包裹可以存放武器、防具、消耗品,以及包裹。它可以無限次的迭代,形成樹狀,如下所示:

  以上的模型反應了組合(Composite)模式的思維。在上述的樹中,我們把節點分為兩種:部分和整體。所謂“部分”,就是指那些沒有子節點的項,如爐石、匕首等;整體是指擁有子節點的項,它可以儲存子節點。組合模式的意圖是將對象組成樹形結構以表示“部分-整體”的階層,使得使用者對單個對象和組合對象的使用具有一致性。

  下面是實現這個機制的Java代碼:

import java.util.ArrayList;interface WowItem {    String getName();    void add(WowItem item);    void remove(WowItem item);    WowItem get(int i);    void print();}class Bag implements WowItem {    ArrayList<WowItem> items = new ArrayList<WowItem>();    public String getName(){        return "背包 ";    }    public void add(WowItem item){        items.add(item);    }    public void remove(WowItem item){        items.remove(item);    }    public WowItem get(int i){        return items.get(i);    }    public void print(){        System.out.println(getName() + "{" );        for ( WowItem i : items){            i.print();        }        System.out.println("}");    }}class Hearthstone implements WowItem {    public String getName(){        return "爐石";    }    public void add(WowItem item){ }    public void remove(WowItem item){ }    public WowItem get(int i){ return null; }    public void print(){        System.out.println(getName());    }}class Dagger implements WowItem {    public String getName(){        return "匕首";    }    public void add(WowItem item){ }    public void remove(WowItem item){ }    public WowItem get(int i){ return null; }    public void print(){        System.out.println(getName());    }}class Composite{    public static void main(String[] args) {        WowItem myBag = new Bag();        WowItem smallBag = new Bag();        myBag.add(new Dagger());        myBag.add(smallBag);        smallBag.add(new Dagger());        myBag.add(new Hearthstone());        myBag.print();    }}

  為了簡化期間,我們構造三個物品:包裹、匕首和爐石。其中,包裹可以容納子物品,匕首和爐石不可以。為了保持一致性(能在同一容器中容納它們),它們必須繼承於同一個類或者介面,在這個例子上它們均繼承於WowItem介面。這個介面聲明了4個方法,分別是表示添加、刪除、擷取某一子物品、列印本物品名稱。有幾點需要注意:1、我採用了ArrayList容器來儲存WowItem,因此所有物品必須繼承WowItem。2、在Bag(包裹)類中,均有對add、remove和get做實現,Bag類中的print會調用其所有子節點的print方法。3、對於非Bag類,如Dagger、Hearthstone,它們沒有子節點,因此對add、remove、get做了空實現(get返回了null),print方法則直接列印出了它們的名字。

  在main方法中,我們定義了個根節點myBag,為它增加了一把匕首Dagger、一個小背包(smallBag),在小背包中添加了一把匕首,然後再在myBag中添加了一個爐石,程式運行結果如下:

背包 {
匕首
背包 {
匕首
}
爐石
}

  最後再說兩個問題:

  一、你可能會發現,對於非組合類別(Dagger、Hearthstone),有許多代碼是多餘的,例如它們不需要實現add、remove、get等方法,如果這些類均繼承於WowItem,代碼編寫會比較繁瑣(因為要每個繼承的方法都要空實現),而且會損失安全性——我們可能一不小心為一個Dagger調用了add方法或者remove方法。因此,你可以選擇為這些非組合類別建立一個另外一個類來管理這些子組件,這樣的話,就喪失了透明性,它讓部分和整體變成了兩個獨立的部分,我是不推薦這麼做的。改善的方法有很多,例如非組合類別都繼承於一個抽象類別A,而這個抽象類別A是繼承於WowItem的,並且實現了add、remove、get方法,均為拋出一個異常。那麼,只要是非組合類別調用了add、remove或get,均會得到一個異常。

  二、組合在實際的使用中用途非常廣。如在編寫介面的時候,用到的控制項機制——有些控制項可以當做“容器”,例如,Frame中可以放入Button、RadioButton,也可以放入Frame,這就是典型的組合模式的運用。


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.