組合模式也叫做“部分-整體”模式,這樣其實定義也就很明顯了,正好和數據結構的知識相對應,把對象組合成樹形結構以表示“部分-整體”的層次結構。
先看類圖:

首先分析一下這個類圖,Leaf和CompZ喎?http://www.Bkjia.com/kf/ware/vc/" target="_blank" class="keylink">vc2l0ZcrHzayxsrXEo6y2vMrHvMyz0Li4wOBDb21wb25lbnSjrNPW0vLOqkNvbXBvbmVudNbQtObU2kxlYWbX08Dgo6zL+dLUy/u6zUNvbXBvbmVudLu5tObU2tfFvtu6z7nYz7U8L3A+CjxwPjxicj4KPC9wPgo8cD4gICAgIL7Z0ru49rrcs6O8+7XEwP3X06OsztLDx8zszOy21NfFtefE1KOsus2499bWzsS8/qOszsS8/rzQtPK9u7XAo6zV4rK7vs3Kx9K7uPa63LrDtdjX6brPxKPKvcLwo788L3A+CjxwPjxzdHJvbmc+wLS/tL+0wODNvKO6PC9zdHJvbmc+PC9wPgo8cD48aW1nIHNyYz0="http://www.2cto.com/uploadfile/Collfiles/20141014/20141014092238331.png" alt="\">
來看看具體的實現代碼:
AbstractFile為組合中的對象聲明接口,實現所有類共有接口的默認行為。
package composite;
import java.util.*; //添加引用
public abstract class AbstractFile {
protected String name; // 定義name字段
public void printName() {
System.out.println(name);
}
// 通常都用add和remove方法來提供增加或移除樹葉或樹枝的功能
public abstract boolean addChild(AbstractFile file); // 增加
public abstract boolean removeChild(AbstractFile file); // 移除
// 一個集合,存放摘要文件的子文件的對象
public abstract List getChildren();
} File為子類文件,繼承父類,也是樹中所謂的葉子節點,葉子節點是沒有子節點的,所以父類所謂的方法並不能實現,返回true和null
package composite;
import java.util.*;
public class File extends AbstractFile {
public File(String name) {
this.name = name;
}
//文件並沒有添加的能力,它只是一個單獨的個體
public boolean addChild(AbstractFile file) {
return false;
}
//對於文件本身,已經是葉子節點了,所以也無刪除子文件的功能
public boolean removeChild(AbstractFile file) {
return false;
}
// 由於File已經是葉子節點了,所以就不存在集合這一說,所以這個方法返回的是空值
public List getChildren() {
return null;
}
} Folder為子類文件夾,同樣也繼承於父類,但是此類只是一個普通的節點,裡邊依舊包含葉子節點。
package composite;
import java.util.*;
public class Folder extends AbstractFile {
private List childList ;
public Folder(String name) {
this.name = name;
//用來建立一個集合保存子文件
this.childList = new ArrayList();
}
//添加子文件
public boolean addChild(AbstractFile file) {
return childList.add(file);
}
//刪除子文件
public boolean removeChild(AbstractFile file) {
return childList.remove(file);
}
// 子類的返回類型應該和父類的定義保持一致
public List getChildren() {
return childList;
}
}
最後來看看客戶端是如何調用和打印的
package composite;
import java.util.List;
public class Client {
public static void main(String[] args) {
// TODO 自動生成的方法存根
// 構造一個樹形的文件、目錄結構
AbstractFile rootFolder = new Folder("c:\\");
AbstractFile compositeFolder = new Folder("composite");
AbstractFile windowsFolder = new Folder("windows");
AbstractFile file = new File("TestComposite.java");
rootFolder.addChild(compositeFolder);
rootFolder.addChild(windowsFolder);
compositeFolder.addChild(file);
// 打印目錄文件樹
printTree(rootFolder);
}
private static void printTree(AbstractFile ifile) {
ifile.printName();
List children = ifile.getChildren();
if (children == null)
return;
for (AbstractFile file : children) {
printTree(file); // 打印方法的調用
}
}
}
透明方式與安全方式
在File子類中,他所謂的各種方法都是不實行的,但是卻依舊存在,這種方式就叫做“透明方式”;這樣做的好處就是葉子節點和枝節點對於外界沒有區別,它們具備完全一致的行為接口;但是問題也會很明顯的,那就是在File中那些所謂的方法的存在是毫無意義的;如果不想讓其做無用功,也就是把File子類中的無意義的方法都去掉,這種方式叫做“安全方式”;但是由於是不透明的,所以他們就不能具有一致的接口了,這樣反而增加了其復雜性,客戶端的調用需要再增加其相應的判斷。
什麼時候使用組合模式?
1)需求中體現的是“部分-整體”的層次的結構時,使用此模式;
2)用戶希望忽略組合對象與單個對象的不同,統一地使用組合結構中的所有的對象的時候,使用此模式;
最後總結:
每個模式其實都是需要慢慢理解的,真正的懂得了它的精髓所在,那當再看到類似的字眼的時候就會有親近的感覺,對於組合模式總結為以下幾點:
組合模式提供一個結構,可同時包容個別對象和組合對象; 允許客戶對個別對象以及組合對象一視同仁; 組合結構內的任意對象都稱為組件,組件可以是組合,也可以是葉子節點; 在實現組合模式時,有許多設計上的折衷。這時候就要就情況選擇透明方式還是安全方式了!