1. 程式人生 > >設計模式讀書筆記-----組合模式

設計模式讀書筆記-----組合模式


       我們對於這個圖片肯定會非常熟悉,這兩幅圖片我們都可以看做是一個檔案結構,對於這樣的結構我們稱之為樹形結構。在資料結構中我們瞭解到可以通過呼叫某個方法來遍歷整個樹,當我們找到某個葉子節點後,就可以對葉子節點進行相關的操作。我們可以將這顆樹理解成一個大的容器,容器裡面包含很多的成員物件,這些成員物件即可是容器物件也可以是葉子物件。但是由於容器物件和葉子物件在功能上面的區別,使得我們在使用的過程中必須要區分容器物件和葉子物件,但是這樣就會給客戶帶來不必要的麻煩,作為客戶而已,它始終希望能夠一致的對待容器物件和葉子物件。這就是組合模式的設計動機:組合模式定義瞭如何將容器物件和葉子物件進行遞迴組合,使得客戶在使用的過程中無須進行區分,可以對他們進行一致的處理。

       一、 模式定義

組合模式組合多個物件形成樹形結構以表示“整體-部分”的結構層次。

組合模式對單個物件(葉子物件)和組合物件(組合物件)具有一致性,它將物件組織到樹結構中,可以用來描述整體與部分的關係。同時它也模糊了簡單元素(葉子物件)和複雜元素(容器物件)的概念,使得客戶能夠像處理簡單元素一樣來處理複雜元素,從而使客戶程式能夠與複雜元素的內部結構解耦。

上面的圖展示了計算機的檔案系統,檔案系統由檔案和目錄組成,目錄下面也可以包含檔案或者目錄,計算機的檔案系統是用遞迴結構來進行組織的,對於這樣的資料結構是非常適用使用組合模式的。

在使用組合模式中需要注意一點也是組合模式最關鍵的地方:葉子物件和組合物件實現相同的介面。這就是組合模式能夠將葉子節點和物件節點進行一致處理的原因。

二、 模式結構


組合模式主要包含如下幾個角色:

1.Component :組合中的物件宣告介面,在適當的情況下,實現所有類共有介面的預設行為。宣告一個介面用於訪問和管理Component子部件。
2.Leaf:葉子物件。葉子結點沒有子結點。
3.Composite:容器物件,定義有枝節點行為,用來儲存子部件,在Component介面中實現與子部件有關操作,如增加(add)和刪除(remove)等。

從模式結構中我們看出了葉子節點和容器物件都實現Component介面,這也是能夠將葉子物件和容器物件一致對待的關鍵所在。

       三、 模式實現

在檔案系統中,可能存在很多種格式的檔案,如果圖片,文字檔案、視訊檔案等等,這些不同的格式檔案的瀏覽方式都不同,同時對資料夾的瀏覽就是對資料夾中檔案的瀏覽,但是對於客戶而言都是瀏覽檔案,兩者之間不存在什麼差別,現在只用組合模式來模擬瀏覽檔案。UML結構圖:


首先是檔案類:File.java

public abstract class File {
    String name;
    
    public File(String name){
        this.name = name;
    }
    
    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public abstract void display();
}

然後是資料夾類:Folder.java,該類包含對檔案的增加、刪除和瀏覽三個方法

public class Folder extends File{
    private List<File> files;
    
    public Folder(String name){
        super(name);
        files = new ArrayList<File>();
    }
    
    /**
     * 瀏覽資料夾中的檔案
     */
    public void display() {
        for(File file : files){
            file.display();
        }
    }
    
    /**
     * @desc 向資料夾中新增檔案
     * @param file
     * @return void
     */
    public void add(File file){
        files.add(file);
    }
    
    /**
     * @desc 從資料夾中刪除檔案
     * @param file
     * @return void
     */
    public void remove(File file){
        files.remove(file);
    }
}


然後是三個檔案類:TextFile.java、ImageFile.java、VideoFile.java

TextFile.java

public class TextFile extends File{

    public TextFile(String name) {
        super(name);
    }

    public void display() {
        System.out.println("這是文字檔案,檔名:" + super.getName());
    }
    
}

ImageFile.java
public class ImagerFile extends File{

    public ImagerFile(String name) {
        super(name);
    }

    public void display() {
        System.out.println("這是影象檔案,檔名:" + super.getName());
    }

}

VideoFile.java
public class VideoFile extends File{

    public VideoFile(String name) {
        super(name);
    }

    public void display() {
        System.out.println("這是影像檔案,檔名:" + super.getName());
    }

}

最後是客戶端
public class Client {
    public static void main(String[] args) {
        /**
         * 我們先建立一個這樣的檔案系統
         *                  總檔案
         *                  
         *   a.txt    b.jpg                   c資料夾              
         *                      c_1.text  c_1.rmvb    c_1.jpg   
         *                                                       
         */ 
        //總資料夾
        Folder zwjj = new Folder("總資料夾");
        //向總資料夾中放入三個檔案:1.txt、2.jpg、1資料夾
        TextFile aText= new TextFile("a.txt");
        ImagerFile bImager = new ImagerFile("b.jpg");
        Folder cFolder = new Folder("C資料夾");
        
        zwjj.add(aText);
        zwjj.add(bImager);
        zwjj.add(cFolder);
        
        //向C資料夾中新增檔案:c_1.txt、c_1.rmvb、c_1.jpg 
        TextFile cText = new TextFile("c_1.txt");
        ImagerFile cImage = new ImagerFile("c_1.jpg");
        VideoFile cVideo = new VideoFile("c_1.rmvb");
        
        cFolder.add(cText);
        cFolder.add(cImage);
        cFolder.add(cVideo);
        
        //遍歷C資料夾
        cFolder.display();
        //將c_1.txt刪除
        cFolder.remove(cText);
        System.out.println("-----------------------");
        cFolder.display();
    }
}

執行結果


       四、 模式優缺點

優點

1、可以清楚地定義分層次的複雜物件,表示物件的全部或部分層次,使得增加新構件也更容易。

2、客戶端呼叫簡單,客戶端可以一致的使用組合結構或其中單個物件。

3、定義了包含葉子物件和容器物件的類層次結構,葉子物件可以被組合成更復雜的容器物件,而這個容器物件又可以被組合,這樣不斷遞迴下去,可以形成複雜的樹形結構。

4、更容易在組合體內加入物件構件,客戶端不必因為加入了新的物件構件而更改原有程式碼。

缺點

1、使設計變得更加抽象,物件的業務規則如果很複雜,則實現組合模式具有很大挑戰性,而且不是所有的方法都與葉子物件子類都有關聯

       五、 模式適用場景

1、需要表示一個物件整體或部分層次,在具有整體和部分的層次結構中,希望通過一種方式忽略整體與部分的差異,可以一致地對待它們。

2、讓客戶能夠忽略不同物件層次的變化,客戶端可以針對抽象構件程式設計,無須關心物件層次結構的細節。

六、 模式總結

1、 組合模式用於將多個物件組合成樹形結構以表示“整體-部分”的結構層次。組合模式對單個物件(葉子物件)和組合物件(容器物件)的使用具有一致性。

2、 組合物件的關鍵在於它定義了一個抽象構建類,它既可表示葉子物件,也可表示容器物件,客戶僅僅需要針對這個抽象構建進行程式設計,無須知道他是葉子物件還是容器物件,都是一致對待。

3、 組合模式雖然能夠非常好地處理層次結構,也使得客戶端程式變得簡單,但是它也使得設計變得更加抽象,而且也很難對容器中的構件型別進行限制,這會導致在增加新的構件時會產生一些問題。

相關推薦

設計模式讀書筆記-----組合模式

       我們對於這個圖片肯定會非常熟悉,這兩幅圖片我們都可以看做是一個檔案結構,對於這樣的結構我們稱之為樹形結構。在資料結構中我們瞭解到可以通過呼叫某個方法來遍歷整個樹,當我們找到某個葉子節點

【大話設計模式讀書筆記——代理模式

oid write 實現 == str href proxy logs i++ 代理模式 代理者是指一個類別可以作為其它東西的接口。代理者可以作任何東西的接口:網絡連接、內存中的大對象、文件或其它昂貴或無法復制的資源。 維基百科-代理模式 代理模式實現遠程圖片加載 /

【大話設計模式讀書筆記——原型模式

class splay 引用類型 play mark 工作經驗 好的 blog 我們 原型模式 原型模式是創建型模式的一種,其特點在於通過“復制”一個已經存在的實例來返回新的實例,而不是新建實例。被復制的實例就是我們所稱的“原型”,這個原型是可定制的。 原型模式多用於創建

設計模式讀書筆記-----原型模式

以前聽過這樣一句話:“程式設計師的最高境界就是Ctrl+C、Ctrl+V”,我們先不論這句話的對錯,就論這個過程,這個過程我們都知道無非就是複製一個物件,然後將其不斷地貼上。這樣的過程我們可以將其稱之為“克隆”。再如我們應聘的時候列印了那麼多的簡歷。        

Head First 設計模式讀書筆記——策略模式

最近研究了一些優秀的開源框架,學習了很多開源框架中自己不熟悉的知識,發現一些優秀的開源框架都或多或少的使用了設計模式,正好為了能分析原始碼不那麼頭疼乾脆先複習一下以前只看過的設計模式,於是我翻出了壓箱底的head first 設計模式,這本書圖文並茂,就是廢話很多不過它完全順

設計模式讀書筆記-工廠模式

單例模式的學習 優化了效能,節省記憶體開支 單例模式一般沒有介面,比較難以拓展,這也意味著難以測試(沒有mock) 單例模式也有執行緒安全問題(懶漢式可能有執行緒安全問題) 如果實現了cloneable介面,並實現了clone方法,則可以直接通過物件複製的形式創

Head First設計模式讀書筆記八 第九章下 組合模式

組合模式+迭代器模式 接著上一節最後的例子,例子的最終list結構圖是這樣的: 若要給DinerMenu新加一種Menu(即下面這樣),則需要對現有結構進行較大改動。 可以看到,目前的結構中分為兩種結構,一種是menu,是一種容器,可以包含選單項,而第二種

【大話設計模式讀書筆記——開閉原則】

等等 使用方式 價值 log 變更 重用 中間 多種實現 過程 開閉原則 在面向對象編程領域中,開閉原則規定“軟件中的對象(類,模塊,函數等等)應該對於擴展是開放的,但是對於修改是封閉的”[1],這意味著一個實體是允許在不改變它的源代碼的前提下變更它的行為。該特性在產品化

【大話設計模式讀書筆記——工廠方法模式

down 除了 wikipedia override 客戶 class a over dfa mar 工廠方法模式 工廠方法模式的實質是“定義一個創建對象的接口,但讓實現這個接口的類來決定實例化哪個類。工廠方法讓類的實例化推遲到子類中進行。 工廠方法模式 VS 簡單工廠

設計模式讀書筆記(二)--創建型模式

代碼 技術 bst 簡單 應用 接口 擴展 工廠類 prototype 1、創建型模式抽象了實例化過程。他們幫助一個系統獨立於如何創建、組合和表示它的那些對象、一個類創建型模式使用繼承改變被實例化的類,而一個對象創建型模式將實例化委托給另一個對象。 2、回顧一下創建型模式主

js設計模式第四章 工廠方法模式 讀書筆記

對於建立多類物件,簡單工廠就不太實用了。  通過工廠方法模式可以輕鬆的建立多個類的例項物件,而且建立物件的方式避免了使用者與物件類之間的耦合,使用者不必關心建立該物件的具體類,只需呼叫工廠方法即可。 安全的工廠方法模式 var Factory=function(type,con

js設計模式第三章 簡單工廠模式 讀書筆記

簡單工廠模式又叫靜態工廠方法,由一個工廠物件決定建立某一種產品物件類的例項。主要用來建立同一類的物件。 比如提示彈窗類 function createPop(type,text){ //建立一個物件,並對物件拓展屬性和方法 var o = new Object();

HeadFirst設計模式讀書筆記之工廠模式

1. 簡單工廠 1. 你開了一家披薩店,點披薩的方法可能是這樣: public Pizza orderPizza(String type) { Pizza pizza; if (type.equals("芒果披薩")){ pizza = ne

js設計模式第七章 語言之魂——原型模式 讀書筆記

原型模式:用原型例項指向建立物件的類,使用於建立新的物件的類共享原型物件的屬性以及方法。 基於原型鏈實現物件之間的繼承,這種繼承是基於一種對方法或屬性的共享,而不是對方法和屬性的複製。 原型模式就是將可複用的、可共享的、耗時大的從基類中提出來然後放在其原型中,然後子類通過組合繼承或者寄生組合

js設計模式第六章 分既是合——建造者模式 讀書筆記

建造者模式:將一個複雜物件的構建層與其表示層相互分離,同樣的構建過程可採用不同的表示。 工廠模式主要是為了建立物件例項或者類簇,關心的是最終產出的是什麼。不關心你建立的整個過程,僅僅需要知道最終建立的結果。所以通過工廠模式我們得到的都是物件例項或者類簇。 然而建造者模式在建立物件是更為複雜一些,

js設計模式第五章 抽象工廠模式 讀書筆記

抽象工廠模式(Abstract Factory) 通過類的抽象使得業務適用於一個產品類簇的建立,而不負責建立某一類產品的例項。 JS中是沒有直接的抽象類的,因此我們需要在類的方法中丟擲錯誤來模擬抽象類,如果繼承的子類中沒有覆寫該方法而呼叫,就會丟擲錯誤。 //汽車抽象類 var Car = fu

圖解設計模式讀書筆記(七)——Strategy(策略)模式

顧名思義,策略模式一般應用在使用多種策略(演算法)的情況下,比如一些棋牌遊戲中,電腦會有多種策略去應付使用者,如入門級別,高手級別等。 策略模式將操作抽象成介面,具體的演算法由子類實現,有一個上下文環境Context來使用策略進行操作,context只需持有Strategy

圖解設計模式讀書筆記(九)——Decorator(裝飾)模式

應用場景: 最主要的應用場景就是當要增加一些基本功能的排列組合而產生的非常大量的功能時。 舉幾個例子: 1.文中的裝飾顯示的例子,有多種裝飾方式,比如在字串兩邊加 “|”,或者上下加一行“+------+”這種符號,文中只提到對單行的String的裝飾,還可能會有其他型

圖解設計模式讀書筆記(十五)——Memento(備忘錄)模式

使用場景: 需要儲存狀態,以便將來執行redo/undo操作來恢復狀態。多用在棋牌類遊戲,書寫編輯類應用上。 基本思想: 在保證封裝性的基礎上,將類的屬性狀態在外部儲存起來。 保證封裝性的方式起始就是控制好memento類的可見性,即對於敏感資料,不使用public修

圖解設計模式讀書筆記(十一)——Chain of Responsibility(責任鏈)模式

看到這個模式,最先想到的就是okhttp跟Android的事件處理機制了。 使用場景: 當功能出現分層,層級之間相對獨立這種情況,可考慮使用責任鏈模式。 類關係圖: Handler是一個抽象類,它擁有屬性next,型別是自身型別,並有處理請求但request方法。