組合模式也叫做“部分-整體”模式,這樣其實定義也就很明顯了,正好和數據結構的知識相對應,把對象組合成樹形結構以表示“部分-整體”的層次結構。
先看類圖:
首先分析一下這個類圖,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)用戶希望忽略組合對象與單個對象的不同,統一地使用組合結構中的所有的對象的時候,使用此模式;
最後總結:
每個模式其實都是需要慢慢理解的,真正的懂得了它的精髓所在,那當再看到類似的字眼的時候就會有親近的感覺,對於組合模式總結為以下幾點:
組合模式提供一個結構,可同時包容個別對象和組合對象; 允許客戶對個別對象以及組合對象一視同仁; 組合結構內的任意對象都稱為組件,組件可以是組合,也可以是葉子節點; 在實現組合模式時,有許多設計上的折衷。這時候就要就情況選擇透明方式還是安全方式了!