意圖
允許你將對象組合成樹形結構來表現“整體/部分”。組合能讓客戶以一致的方式處理個別對象以及對象組合。
動機
形如:有一個樹形結構的菜單,子菜單和可能還帶有菜單項的子菜單,那麼任何菜單都是一種“組合”。因爲它既可以包含其他菜單,也可以包含菜單項。我們可以使用組合模式設計、編碼,從而對整個菜單結構應用相同的操作。
適用性
組合模式主要的應用場景:
- 在需要表示一個對象整體與部分的層次結構的場合。
- 要求對用戶隱藏組合對象與單個對象的不同,用戶可以用統一的接口使用組合結構中的所有對象的場合。
結構
組合模式包含以下主要角色:
- 抽象組件(
Component
):爲分支節點和葉子節點聲明公共接口,並實現其默認方法。在透明式的組合模式中抽象組件還聲明訪問和管理子類的接口;在安全式的組合模式中不聲明訪問和管理子類的接口,管理工作由分支節點完成。 - 分支節點(
Composite
):有子節點,實現了抽象構件角色中聲明的接口,主要作用是存儲和管理子部件,包含 add()、remove()、getChild() 等方法。 - 葉子節點(
Leaf
):沒有子節點,用於實現抽象構件角色中聲明的公共接口。
組合模式分爲透明式的組合模式和安全式的組合模式。
- 透明式
- 安全式
實現
以透明式爲例
// 抽象組件
public interface Component {
void add(Component com);
void remove(Component com);
Component getChild(int i);
void operation();
}
// 分支節點
public class Composite implements Component {
private List<Component> children = new ArrayList<Component>(16);
@Override
public void add(Component com) {
children.add(com);
}
@Override
public void remove(Component com) {
children.remove(com);
}
@Override
public Component getChild(int i) {
return children.get(i);
}
@Override
public void operation() {
for (Component c : children) {
c.operation();
}
}
}
// 葉子節點
public class Leaf implements Component {
private String name;
public Leaf(String name) {
this.name = name;
}
@Override
public void add(Component com) {}
@Override
public void remove(Component com) {}
@Override
public Component getChild(int i) {
return null;
}
@Override
public void operation() {
System.out.println("葉子節點 "+name+" 被訪問。。。");
}
}
//測試客戶端,透明方式的組合模式
public class TestClient {
public static void main(String[] args) {
Component c0 = new Composite();
Component c1 = new Composite();
Component leaf1 = new Leaf("leaf1");
Component leaf2 = new Leaf("leaf2");
Component leaf3 = new Leaf("leaf3");
c0.add(leaf1);
c0.add(c1);
c1.add(leaf2);
c1.add(leaf3);
c0.operation();
}
}
已知應用
- javax.swing.JComponent#add(Component)
- java.awt.Container#add(Component)
- java.util.Map#putAll(Map)
- java.util.List#addAll(Collection)
- java.util.Set#addAll(Collection)
相關模式
參考資料
- 《
Head First
設計模式》 - 圖說設計模式
- Java設計模式:23種設計模式全面解析(超級詳細)