組合模式
有時又叫做部分-整體模式(Part-Whole) 。組合模式將對象組織到樹結構中,可以用來描述整體與部分的關係。組合模式可以使客戶端將單純元素與複合元素同等看待。
何時使用
- 需求中是體現部分與整體層次的結構時
- 希望用戶忽略組合對象與單個對象的不同, 統一的使用組合結構中的所有對象時
優點
- 定義了包含基本對象和組合對象的類層次結構
基本對象可以組合成組合對象,組合對象又能組合成更復雜的組合對象,可以不斷地遞歸組合下去,從而構成-一個統一的組 合對象的類層次結構 - 統一了組合對象和葉子對象
- 簡化了客戶端調用
不用區分組合對象和葉子對象 - 更容易擴展
由於客戶端是統一的面對Component來操作,因此,新定義的Composite或leaf子類能夠很容易的與已有的結構一起工作,而不需改變客戶端
缺點
- 很難限制組合中的組件類型
這是容易添加新的組件帶來的問題,在需要檢測組件類型的時候,使得我們不能依靠編譯期的類型約束來完成,必須在運行期間動態檢測
本質
- 統一葉子對象和組合對象
角色
- 抽象構件(Component)角色:這是一個抽象角色,它給參與組合的對象規定一個接口。這個角色給出共有接口及其默認行爲。
- 樹葉構件(Leaf)角色:代表參加組合的樹葉對象。一個樹葉對象沒有下級子對象。
- 樹枝構件(Composite)角色:代表參加組合的有子對象的對象,並給出樹枝構件對象的行爲。
組合模式的目的
- 讓客戶端不再區分操作的是組合對象還是葉子對象,而是以一種統一的方式來操作
對象樹
- 組合模式會組合出樹形結構來,這也就意味着,所有可以使用對象樹來描述或操作的功能,都可以考慮使用組合模式。
組合模式的實現根據所實現接口的區別分爲兩種形式,分別稱爲安全模式和透明模式。( 優缺點是互補的) 組合模式可以不提供父對象的管理方法,但組合模式必須在合適的地方提供子對象的管理方法(諸如add、remove、Display等)。
商品識別樹代碼及UML圖如下
根節點:
public abstract class Component {
protected String name;
public Component(String name) {
super();
this.name = name;
}
public abstract void add(Component component);
public abstract void remove(Component component);
public abstract void display(int dept);
}
葉子結點:
public class Leaf extends Component {
/**
* @param name
*/
public Leaf(String name) {
super(name);
// TODO Auto-generated constructor stub
}
@Override
public void add(Component component) {
System.out.println("Cannot add to a leaf");
}
@Override
public void remove(Component component) {
System.out.println("Cannot remove from a leaf");
}
@Override
public void display(int dept) {
String str="";
for(int i=0;i<dept;i++) {
str+="-";
}
System.out.println(str+name);
}
}
樹枝:
public class Composite extends Component {
private List<Component>children=new ArrayList<Component>();
public Composite(String name) {
super(name);
}
@Override
public void add(Component component) {
children.add(component);
}
@Override
public void remove(Component component) {
children.remove(component);
}
@Override
public void display(int dept) {
String str="";
for(int i=0;i<dept;i++) {
str+="-";
}
System.out.println(str+name);
for (Component component : children) {
component.display(dept + 2);
}
}
}
客戶端:
public class Main {
public static void main(String[] args) {
System.out.println("商品識別樹");
Component root = new Composite("服裝");
Composite comp1 = new Composite("男裝");
comp1.add(new Leaf("襯衣"));
comp1.add(new Leaf("夾克"));
root.add(comp1);
Composite comp2 = new Composite("女裝");
comp2.add(new Leaf("襯衣"));
comp2.add(new Leaf("夾克"));
root.add(comp2);
root.display(1);
}
}