java设计模式组合模式详解_《JAVA设计模式》之组合模式(Composite)
在閻宏博士的《JAVA與模式》一書中開頭是這樣描述合成(Composite)模式的:html
合成模式屬于對象的結(jié)構(gòu)模式,有時又叫作“部分——總體”模式。合成模式將對象組織到樹結(jié)構(gòu)中,能夠用來描述總體與部分的關(guān)系。合成模式可使客戶端將單純元素與復(fù)合元素同等看待。java
合成模式
合成模式把部分和總體的關(guān)系用樹結(jié)構(gòu)表示出來。合成模式使得客戶端把一個個單獨(dú)的成分對象和由它們復(fù)合而成的合成對象同等看待。安全
好比,一個文件系統(tǒng)就是一個典型的合成模式系統(tǒng)。下圖是常見的計(jì)算機(jī)XP文件系統(tǒng)的一部分。ide
從上圖能夠看出,文件系統(tǒng)是一個樹結(jié)構(gòu),樹上長有節(jié)點(diǎn)。樹的節(jié)點(diǎn)有兩種,一種是樹枝節(jié)點(diǎn),即目錄,有內(nèi)部樹結(jié)構(gòu),在圖中涂有顏色;另外一種是文件,即樹葉節(jié)點(diǎn),沒有內(nèi)部樹結(jié)構(gòu)。post
顯然,能夠把目錄和文件當(dāng)作同一種對象同等對待和處理,這也就是合成模式的應(yīng)用。this
合成模式能夠不提供父對象的管理方法,可是合成模式必須在合適的地方提供子對象的管理方法,諸如:add()、remove()、以及getChild()等。url
合成模式的實(shí)現(xiàn)根據(jù)所實(shí)現(xiàn)接口的區(qū)別分為兩種形式,分別稱為安全式和透明式。spa
安全式合成模式的結(jié)構(gòu)
安全模式的合成模式要求管理匯集的方法只出如今樹枝構(gòu)件類中,而不出如今樹葉構(gòu)件類中。
.net
這種形式涉及到三個角色:code
● 抽象構(gòu)件(Component)角色:這是一個抽象角色,它給參加組合的對象定義出公共的接口及其默認(rèn)行為,能夠用來管理全部的子對象。合成對象一般把它所包含的子對象當(dāng)作類型為Component的對象。在安全式的合成模式里,構(gòu)件角色并不定義出管理子對象的方法,這必定義由樹枝構(gòu)件對象給出。
● 樹葉構(gòu)件(Leaf)角色:樹葉對象是沒有下級子對象的對象,定義出參加組合的原始對象的行為。
● 樹枝構(gòu)件(Composite)角色:表明參加組合的有下級子對象的對象。樹枝構(gòu)件類給出全部的管理子對象的方法,如add()、remove()以及getChild()。
源代碼
抽象構(gòu)件角色類
public interfaceComponent {
/*** 輸出組建自身的名稱 */ public voidprintStruct(String preStr); }
樹枝構(gòu)件角色類
public class Composite implementsComponent {
/*** 用來存儲組合對象中包含的子組件對象 */ private List childComponents = new ArrayList(); /*** 組合對象的名字 */ privateString name; /*** 構(gòu)造方法,傳入組合對象的名字 * @paramname 組合對象的名字 */ publicComposite(String name){ this.name =name; } /*** 匯集管理方法,增長一個子構(gòu)件對象 * @paramchild 子構(gòu)件對象 */ public voidaddChild(Component child){ childComponents.add(child); } /*** 匯集管理方法,刪除一個子構(gòu)件對象 * @paramindex 子構(gòu)件對象的下標(biāo) */ public void removeChild(intindex){ childComponents.remove(index); } /*** 匯集管理方法,返回全部子構(gòu)件對象 */ public ListgetChild(){ returnchildComponents; } /*** 輸出對象的自身結(jié)構(gòu) * @parampreStr 前綴,主要是按照層級拼接空格,實(shí)現(xiàn)向后縮進(jìn) */@Override public voidprintStruct(String preStr) { //先把本身輸出 System.out.println(preStr + "+" + this.name); //若是還包含有子組件,那么就輸出這些子組件對象 if(this.childComponents != null){ //添加兩個空格,表示向后縮進(jìn)兩個空格 preStr += " "; //輸出當(dāng)前對象的子對象 for(Component c : childComponents){ //遞歸輸出每一個子對象 c.printStruct(preStr); } } } }
樹葉構(gòu)件角色類
public class Leaf implementsComponent {
/*** 葉子對象的名字 */ privateString name; /*** 構(gòu)造方法,傳入葉子對象的名稱 * @paramname 葉子對象的名字 */ publicLeaf(String name){ this.name =name; } /*** 輸出葉子對象的結(jié)構(gòu),葉子對象沒有子對象,也就是輸出葉子對象的名字 * @parampreStr 前綴,主要是按照層級拼接的空格,實(shí)現(xiàn)向后縮進(jìn) */@Override public voidprintStruct(String preStr) { //TODO Auto-generated method stub System.out.println(preStr + "-" +name); } }
客戶端類
public classClient {
public static voidmain(String[]args){ Composite root = new Composite("服裝"); Composite c1 = new Composite("男裝"); Composite c2 = new Composite("女裝"); Leaf leaf1 = new Leaf("襯衫"); Leaf leaf2 = new Leaf("夾克"); Leaf leaf3 = new Leaf("裙子"); Leaf leaf4 = new Leaf("套裝"); root.addChild(c1); root.addChild(c2); c1.addChild(leaf1); c1.addChild(leaf2); c2.addChild(leaf3); c2.addChild(leaf4); root.printStruct(""); } }
能夠看出,樹枝構(gòu)件類(Composite)給出了addChild()、removeChild()以及getChild()等方法的聲明和實(shí)現(xiàn),而樹葉構(gòu)件類則沒有給出這些方法的聲明或?qū)崿F(xiàn)。這樣的作法是安全的作法,因?yàn)檫@個特色,客戶端應(yīng)用程序不可能錯誤地調(diào)用樹葉構(gòu)件的匯集方法,由于樹葉構(gòu)件沒有這些方法,調(diào)用會致使編譯錯誤。
安全式合成模式的缺點(diǎn)是不夠透明,由于樹葉類和樹枝類將具備不一樣的接口。
透明式合成模式的結(jié)構(gòu)
與安全式的合成模式不一樣的是,透明式的合成模式要求全部的具體構(gòu)件類,不論樹枝構(gòu)件仍是樹葉構(gòu)件,均符合一個固定接口。
源代碼
抽象構(gòu)件角色類
public abstract classComponent {
/*** 輸出組建自身的名稱 */ public abstract voidprintStruct(String preStr); /*** 匯集管理方法,增長一個子構(gòu)件對象 * @paramchild 子構(gòu)件對象 */ public voidaddChild(Component child){ /*** 缺省實(shí)現(xiàn),拋出異常,由于葉子對象沒有此功能 * 或者子組件沒有實(shí)現(xiàn)這個功能 */ throw new UnsupportedOperationException("對象不支持此功能"); } /*** 匯集管理方法,刪除一個子構(gòu)件對象 * @paramindex 子構(gòu)件對象的下標(biāo) */ public void removeChild(intindex){ /*** 缺省實(shí)現(xiàn),拋出異常,由于葉子對象沒有此功能 * 或者子組件沒有實(shí)現(xiàn)這個功能 */ throw new UnsupportedOperationException("對象不支持此功能"); } /*** 匯集管理方法,返回全部子構(gòu)件對象 */ public ListgetChild(){ /*** 缺省實(shí)現(xiàn),拋出異常,由于葉子對象沒有此功能 * 或者子組件沒有實(shí)現(xiàn)這個功能 */ throw new UnsupportedOperationException("對象不支持此功能"); } }
樹枝構(gòu)件角色類,此類將implements Conponent改成extends Conponent,其余地方無變化。
public class Composite extendsComponent {
/*** 用來存儲組合對象中包含的子組件對象 */ private List childComponents = new ArrayList(); /*** 組合對象的名字 */ privateString name; /*** 構(gòu)造方法,傳入組合對象的名字 * @paramname 組合對象的名字 */ publicComposite(String name){ this.name =name; } /*** 匯集管理方法,增長一個子構(gòu)件對象 * @paramchild 子構(gòu)件對象 */ public voidaddChild(Component child){ childComponents.add(child); } /*** 匯集管理方法,刪除一個子構(gòu)件對象 * @paramindex 子構(gòu)件對象的下標(biāo) */ public void removeChild(intindex){ childComponents.remove(index); } /*** 匯集管理方法,返回全部子構(gòu)件對象 */ public ListgetChild(){ returnchildComponents; } /*** 輸出對象的自身結(jié)構(gòu) * @parampreStr 前綴,主要是按照層級拼接空格,實(shí)現(xiàn)向后縮進(jìn) */@Override public voidprintStruct(String preStr) { //先把本身輸出 System.out.println(preStr + "+" + this.name); //若是還包含有子組件,那么就輸出這些子組件對象 if(this.childComponents != null){ //添加兩個空格,表示向后縮進(jìn)兩個空格 preStr += " "; //輸出當(dāng)前對象的子對象 for(Component c : childComponents){ //遞歸輸出每一個子對象 c.printStruct(preStr); } } } }
樹葉構(gòu)件角色類,此類將implements Conponent改成extends Conponent,其余地方無變化。
public class Leaf extendsComponent {
/*** 葉子對象的名字 */ privateString name; /*** 構(gòu)造方法,傳入葉子對象的名稱 * @paramname 葉子對象的名字 */ publicLeaf(String name){ this.name =name; } /*** 輸出葉子對象的結(jié)構(gòu),葉子對象沒有子對象,也就是輸出葉子對象的名字 * @parampreStr 前綴,主要是按照層級拼接的空格,實(shí)現(xiàn)向后縮進(jìn) */@Override public voidprintStruct(String preStr) { //TODO Auto-generated method stub System.out.println(preStr + "-" +name); } }
客戶端類的主要變化是再也不區(qū)分Composite對象和Leaf對象。
public classClient {
public static voidmain(String[]args){ Component root = new Composite("服裝"); Component c1 = new Composite("男裝"); Component c2 = new Composite("女裝"); Component leaf1 = new Leaf("襯衫"); Component leaf2 = new Leaf("夾克"); Component leaf3 = new Leaf("裙子"); Component leaf4 = new Leaf("套裝"); root.addChild(c1); root.addChild(c2); c1.addChild(leaf1); c1.addChild(leaf2); c2.addChild(leaf3); c2.addChild(leaf4); root.printStruct(""); } }
能夠看出,客戶端無需再區(qū)分操做的是樹枝對象(Composite)仍是樹葉對象(Leaf)了;對于客戶端而言,操做的都是Component對象。
兩種實(shí)現(xiàn)方法的選擇
這里所說的安全性合成模式是指:從客戶端使用合成模式上看是否更安全,若是是安全的,那么就不會有發(fā)生誤操做的可能,能訪問的方法都是被支持的。
這里所說的透明性合成模式是指:從客戶端使用合成模式上,是否須要區(qū)分究竟是“樹枝對象”仍是“樹葉對象”。若是是透明的,那就不用區(qū)分,對于客戶而言,都是Compoent對象,具體的類型對于客戶端而言是透明的,是無須關(guān)心的。
對于合成模式而言,在安全性和透明性上,會更看重透明性,畢竟合成模式的目的是:讓客戶端再也不區(qū)分操做的是樹枝對象仍是樹葉對象,而是以一個統(tǒng)一的方式來操做。
并且對于安全性的實(shí)現(xiàn),須要區(qū)分是樹枝對象仍是樹葉對象。有時候,須要將對象進(jìn)行類型轉(zhuǎn)換,卻發(fā)現(xiàn)類型信息丟失了,只好強(qiáng)行轉(zhuǎn)換,這種類型轉(zhuǎn)換必然是不夠安全的。
所以在使用合成模式的時候,建議多采用透明性的實(shí)現(xiàn)方式。
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的java设计模式组合模式详解_《JAVA设计模式》之组合模式(Composite)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 想要入坑机器学习?这是MIT在读博士的A
- 下一篇: Bootstrap-select使用说明