描述
定義
將對象組合成樹形結構以表示“部分-整體”的層次結構。Composite使得用戶對單個對象和組合對象的使用具有一致性。
類型
對象結構型模式
UML類圖
實現
主要角色
- Component:抽象構件
- 爲組合中的對象聲明接口。
- 在適當的情況下,實現所有類共有接口的缺省行爲。
- 聲明一個接口用於訪問和管理Component的子組件。
- (可選)在遞歸結構中定義一個接口,用於訪問一個父部件,並在合適的情況下實現它。
- Leaf:樹葉構件
- 在組合中表示葉節點對象,葉節點沒有子節點。
- 在組合中定義圖元對象的行爲。
- Composite:樹枝構件
- 定義有子部件的那些部件的行爲。
- 存儲子部件。
- 在Component接口中實現與子部件有關的操作。
- Client:客戶端類
- 通過Component接口操縱組合部件的對象。
安全模式 VS 透明模式
組合模式的實現根據所實現接口的區別分爲兩種形式:安全模式和透明模式。安全模式要求管理子組件的方法只出現在樹枝構件類中,而不出現在樹葉構件中。而透明模式要求所有的具體構件類,不論樹枝構件還是樹葉構件,均符合同一個固定的接口。
對於組合模式而言,在安全性和透明性上,會更看重透明性,畢竟組合模式的目的是:讓客戶端不再區分操作的是樹枝對象還是樹葉對象,而是以一個統一的方式來操作。而且對於安全性的實現,需要區分的是樹枝對象還是樹葉對象。有時候,需要將對象進行類型強行轉換,這種類型轉換必然是不夠安全的。
因此在使用組合模式的時候,建議多采用透明式的實現方式。
透明模式代碼示例
-
Component:抽象構件
public abstract class Component { public void operation(); // 安全模式中下面接口方法只位於組合構件中 public abstract void add(Component component); public abstract void remove(Component component); public abstract List<Component> getChildren(); }
-
Leaf:樹葉構件
public class Leaf extends Component { public void operation() { System.out.println("Leaf component"); } public void add(Component component) { throw new UnsupportedOperationException("對象不支持此功能"); } public void remove(Component component) { throw new UnsupportedOperationException("對象不支持此功能"); } // 空實現 public List<Component> getChildren() { return new ArrayList<Component>(); } }
-
Composite:樹枝構件
public class Composite extends Component { // 構件容器 private ArrayList<Component> componentArrayList = new ArrayList<Component>(); public void add(Component component) { this.componentArrayList.add(component); } public void remove(Component component) { this.componentArrayList.remove(component); } public List<Component> getChildren() { return this.componentArrayList; } public operation() { for (Component c: componentArrayList) { c.operation(); } } }
-
Client:客戶端類
public class Client { public static void main(String[] args) { Composite root = new Composite(); Leaf leaf = new Leaf(); leaf.operation(); root.add(leaf); root.operation(); } }
適用場景
- 需要表示對象的部分-整體層次結構。
- 希望用戶忽略組合對象與單個對象的不同,用戶將統一地使用組合結構中的所有對象。
優點
- 簡化了客戶端代碼。Composite模式採用樹形結構來實現普遍存在的對象容器,從而將“一對多”的關係轉化爲“一對一”的關係,使得客戶代碼可以一致地處理對象和對象容器,無需關心處理的是單個的對象,還是組合的對象容器。
- 對樹形結構的複雜對象容易控制。組合模式爲樹形結構的面向對象實現提供了一種靈活的解決方案,通過葉子對象和容器對象的遞歸組合,可以形成複雜的樹形結構,但對樹形結構的控制卻非常簡單。
- 增加新構件很方便。無須對現有類庫進行任何修改,符合“開閉原則”。
缺點
- 使得設計更加複雜,客戶端需要花更多時間理清類之間的層次關係。
- 在增加新構件時很難對容器中的構件類型進行限制。在需要檢測組件類型時,不能依靠編譯期的類型約束來實現,必須在運行期間動態檢測。
相關模式
- 通常部件-父部件連接用於Responsibility of Chain模式。
- Decorator模式經常與Composite模式一起使用。當裝飾和組合一起使用時,它們通常有一個公共的父類。因此裝飾必須支持具有add、remove和getChildren操作的Component接口。
- Flyweight讓你共享組件,但不再能引用他們的父部件。
- (迭代器模式)Itertor可用來遍歷Composite。
- Visitor將本來應該分佈在Composite和Leaf類中的操作和行爲局部化。