組合模式 合成模式 COMPOSITE 結構型 設計模式(十一)

組合模式(合成模式 COMPOSITE)

意圖

將對象組合成樹形結構以表示「部分-總體」的層次結構。
Composite使得用戶對單個對象和組合對象的使用具備一致性。
 

樹形結構介紹

爲了便於理解,咱們先介紹一下樹形結構
什麼是樹形結構?
windows系統的文件夾樹形結構,部門組織架構,行政區...都是一種樹形結構
對於最終的節點,稱之爲葉子;不然是樹枝
image_5bfcb125_23eb
 
對於樹形結構常常會有一種使用場景:對他們下發一致性的指令
好比:對於操做系統有刪除操做,便可以刪除一個文件,也能夠刪除一個文件夾,包括他下面全部的文件
相似刪除操做這種命令,並不關心這究竟是一個文件(葉子)仍是一個文件夾(樹枝),關心在乎的只是要刪除目標
可是對於不一樣的類型,文件(葉子)仍是 文件夾(樹枝),他們的處理又的確是不一樣的
文件只須要刪除就能夠了,文件夾還須要遞歸遍歷內部的文件夾,直至全部的葉子節點,而且將他們所有刪除
這就出現了一個矛盾
客戶端其實並不關心究竟是葉子仍是樹枝
可是他卻不得不「關心」,由於他須要分狀況處理
 
客戶端固然但願不關注目標的具體類型也就是但願可以知足依賴倒置原則,不關注具體類型,面向抽象進行編程
最簡單的方法就是將葉子和樹枝抽象出來一種新的類型組件
image_5bfcb125_7b9d
如此一來,刪除操做僅僅關心組件類型,不在關注究竟是葉子仍是樹枝
組件提供統一的協議約定,葉子和樹枝共同實現,將它們的不一樣點的細節封裝到他們內部的方法中
這就可以讓用戶「單個對象和組合對象的使用具備一致性」。 
因此,組合模式就是對於樹形結構場景下的一種使用模式
 
共同的抽象提取爲新的組件Component,能夠表示葉子或者樹枝
可是須要注意到:樹枝能夠有多個樹葉組成,樹枝上面也多是樹枝,也就是說,做爲樹枝的節點,也會包含Component
因此完整的結構圖爲:
image_5bfcb125_50f5
 
因此組合模式的意圖,從結構圖中的Component中就能夠看出來
他們都是Component,因此具備一致性。
藉助於Composite與Component的關係,又可以表述總體與部分的關係。

結構

image_5bfcb125_3a4e
 
 
Component 抽象構建角色
根據單個對象和組合對象的特色,規定的一個抽象角色(接口或抽象類),定義了共同的行爲
或者說將"總體"和"部分"提取共性,進行抽象提取。
Leaf 葉子角色
參與組合對象的單個對象,也就是定義了參加組合對象的原始根本對象的行爲
葉子節點下沒有下級對象
Composite組合對象角色
也就是樹枝角色,單個對象組合起來的一個對象,由多個單一對象構成
而且給出組合對象的行爲(實現Component約定的行爲)
Client客戶端角色
給單個對象或者組合對象施加命令,也就是調用Component中的方法,好比刪除行爲

示例代碼

以刪除文件爲例
FileSystem文件系統類 擁有刪除方法delete() 
他有兩個實現類文件 File 和文件夾Folder
Folder中能夠有文件和文件夾,使用內部的List<FileSystem>保存  
File的delete方法直接刪除,Folder則會便利內部的List<FileSystem>  逐個刪除
package composite;
public interface FileSystem {
void delete();
}
package composite;
public class File implements FileSystem {
@Override
public void delete() {
System.out.println("delete file...");
}
}
package composite;
import java.util.ArrayList;
import java.util.List;
 
public class Folder implements FileSystem {
    List<FileSystem> fileSystemList = new ArrayList<>();
    @Override
    public void delete() {
        for(FileSystem fileSystem:fileSystemList){
            fileSystem.delete();
        }
    }
    public void add(FileSystem fileSystem){
        fileSystemList.add(fileSystem);
    }
}

 

image_5bfcb125_614
 
客戶端
package composite;
public class Client {
    public static void del(FileSystem fileSystem){
        fileSystem.delete();
        System.out.println("DELETED");
        System.out.println();
    }
 
    public static void main(String[] args){
        Folder folder = new Folder();
         
        Folder folder1 = new Folder();
        Folder folder2 = new Folder();
        Folder folder3 = new Folder();
         
        File file1 = new File();
        File file2 = new File();
        File file3 = new File();
        File file4 = new File();
         
        folder.add(file1);
        folder.add(folder1);
        folder.add(folder2);
         
        folder1.add(file2);
        folder1.add(folder3);
        folder3.add(file4);
         
        folder2.add(file3);
        
        del(folder);
        del(folder1);
        del(file2);
        del(folder2);
    }
}

 

 

客戶端Client中    del(FileSystem fileSystem) 方法用於對整個組件進行命令下達
內部調用組件FileSystem的delete方法
經過文件夾Folder的add方法咱們構建了下面這種形式的樹形結構
image_5bfcb125_7f82
經過下面代碼進行測試

        del(folder); html

        del(folder1); java

        del(file2); web

        del(folder2); 編程

 

image_5bfcb125_6062
 
在示例代碼中,藉助於FileSystem這一抽象的組件Componet
將File 這一Leaf角色和 Folder 這一Composite角色  組織成 「部分--總體」的樹形結構
而且,對於客戶端提供統一的外在形式----Component
使得客戶端對單個對象和組合對象的使用具備一致性
這就是組合模式的運用
 

兩種形式

若是你有留意,能夠看獲得前面的代碼示例中
FileSystem中僅僅只有一個delete方法
File也實現了這一個方法,可是Folder 中卻有了add方法
也就是說,Composite角色中有與Component中不一樣的方法!
 
樹枝中能夠有樹枝或者葉子節點,也就是組合對象中能夠包含組合對象或者單一對象
那麼,也就是說:組合對象要提供子對象的管理方法,好比上面的add  可能還會有remove等
上面的例子中,咱們將add方法安置於Composite 中
這被稱爲安全方式的合成模式
由於是在Composite中管理子對象,葉子節點類型的對象根本就沒有這些方法,因此也不能對客戶端執行這些方法
可是,葉子節點和樹枝節點不夠透明,他們擁有不一樣的方法
 
另一種是將子對象的管理所有託管在Component中
也就是葉子節點和樹枝節點都將擁有這些方法,方法都是同樣的,對客戶端來講,葉子和樹枝在方法接口層面上的區別沒有了
客戶端能夠徹底同等的對待它們二者,這就是透明方式的合成模式
可是,它不夠安全,由於葉子節點和樹枝節點邏輯上原本就是不相同的
葉子節點也不會有下一級子節點,因此這些方法沒有意義,並且若是使用編譯期間也不會報錯,會把問題留到運行中
 
兩種方式中,透明就不夠安全,安全就不透明,因此根據實際狀況按照需求進行選擇

總結

組合模式的根本在於抽象組件,對於具備總體與部分關係的事物,若是須要一致性的外在表現,就能夠提取共性進行抽象,這就是組合模式。
將相關聯的對象組織成「部分--總體」的樹形結構形式,經過抽象構建,全部的節點都是Component
對於客戶端來講,無論究竟是Leaf仍是Composite,他們都是Component
高層模塊並不須要關心,處理的究竟是單個對象仍是組合的對象
只要是比較符合「部分--總體」關係,或者說是樹形結構,以及當你但願用戶能夠忽略組合對象和單個對象的區別時,那麼就能夠考慮使用組合模式 
當增長新類型組件時,新定義的Composite或者Leaf子類自動的與已有的結構和客戶代碼一塊兒工做
客戶端程序不須要所以而變化,從這個角度看,符合開閉原則。
相關文章
相關標籤/搜索