組合模式學習筆記
軟件產品設計過程會遇到諸如遍歷文件夾和文件的情況(這只是一種情況,還有部分和員工),而在文件夾裏面可能還會存在文件夾和文件,那麼如果要統一對文件夾和文件進行某些操作(比如殺毒)那麼我們該怎麼進行呢?這裏就需要使用組合模式來進行設計。
組合模式爲處理樹形結構提供了一種較爲完美的解決方案,它描述瞭如何將容器和葉子進行遞歸組合,使得用戶在使用時無須對它們進行區分,可以一致地對待容器和葉子。(在上面的例子中,文件夾就是容器而文件就是葉子)。
組合模式:組合多個對象形成樹形結構以表示具有“整體-部分”關係的層次結構。組合模式對單個對象(即葉子對象)和組合對象(即容器對象)的使用具有一致性,組合模式又可以稱爲”整體-部分”模式,它是一種對象結構型模式
個人認爲,組合模式中將容器類和葉子類共同的方法行爲都抽象出來,形成一個抽象的父類,而葉子類對於行爲進行真正的實現,而在容器類裏面,該方法會進行遞歸的調用,最後仍然會調用到葉子類的方法,客戶端類只需要和抽象類打交道就好,無須關係整個系統區分的葉子和容器
下圖是組合模式的結構圖:
從上面可以看出組合模式一共含有三種角色:
Component抽象構件,通過將容器和葉子共有的方法抽象出來形成抽象構件類,該類裏面聲明瞭子類所有的行爲接口。
Leaf葉子構件:葉子構件類裏面實現了抽象構件中定義的行爲,它不能包含其他葉子。
Composite容器構件:作爲抽象構件的子類,它同樣也是含有所有的行爲接口的,而對於它含有的子容器或者葉子,統一都是遞歸的調用業務方法。
抽象構件既可以代表葉子,也可以代表容器,客戶端就可以通過抽象容器直接處理。
實現代碼:
abstract class Component {
public abstract void operation();
public abstract void add(Component c);
public abstract void remove(Component c);
}
class Leaf extends Component {
public void operation(){
/*TODO*/
}
//當然這裏還有add remove等方法的實現
}
class Composite extends Component {
private ArrayList<Component> list = new ArrayList<Component>();
public void operation(){
for(Object obj:list) {
((Component)obj).operation();
}
}
//同樣這裏也有add和remove方法實現
}
那麼在客戶端調用的時候:
class Client {
public static void main(String args[]) {
Component file1 = new Leaf();
Component file2 = new Leaf();
Component file3 = new Leaf();
Component folder1 = new Composite();
folder1.add(file2);
folder1.add(file3);
folder1.operation();
}
}
從上面客戶端使用的代碼可以看出客戶類對葉子和容器是不可見的,統一通過Component抽象構件類進行編程,而對於容器類的操作,而依次遍歷list裏面的成員,如果某個成員又是子容器類的話,那麼就會遞歸的再進行子容器類的operation操作。
對於上面的代碼中,抽象構件聲明的add和remove方法大家可能會有疑惑,因爲在葉子類中是不應該有這兩個接口的實現的,畢竟葉子再也不能包含葉子或者容器了。那如果所有的方法都聲明在抽象構件中,那麼葉子結點裏面實現的時候就需要對這兩個方法進行出錯提醒,而在容器類中則沒問題。對於這個問題有兩種解決方法。
第一種,我們可以把諸如葉子類不支持的方法移除抽象構件,讓它僅僅包含葉子和容器共同有的行爲,這樣子的話葉子就無須支持add和remove,而容器類中我們可以單獨增加add和remove方法,但是這樣子一來客戶類使用的時候就不能統一使用抽象構件類來聲明容器類(因爲容器類中很多方法Component不支持),否則的話就會導致容器類新增的接口對於客戶類不可見。這屬於安全組合模式。
第二種,是將所有的行爲都在Component類中進行默認定義,那麼在Leaf類中無須處理,容器類中重寫這些方法行爲就好,但是因爲在客戶類看來,這種方式中的葉子結點和容器結點行爲方法都是相同的,因此還是屬於透明組合模式。
總結:
組合模式可以很清楚地分清楚層次對象,對於系統中的組合對象和單個對象,組合模式是統一對待的,簡化了客戶端的代碼。組合模式使得在具有整體和部分的層次結構中的設計忽略掉整體和部分的差異,統一對待。