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