# 樹形結構的處理——組合模式(一)
樹形結構在軟件中隨處可見,例如操作系統中的目錄結構、應用軟件中的菜單、辦公系統中的公司組織結構等等,如何運用面向對象的方式來處理這種樹形結構是組合模式需要解決的問題,組合模式通過一種巧妙的設計方案使得用戶可以一致性地處理整個樹形結構或者樹形結構的一部分,也可以一致性地處理樹形結構中的葉子節點(不包含子節點的節點)和容器節點(包含子節點的節點)。下面將學習這種用于處理樹形結構的組合模式。
11.1 設計殺毒軟件的框架結構
Sunny軟件公司欲開發一個殺毒(AntiVirus)軟件,該軟件既可以對某個文件夾(Folder)殺毒,也可以對某個指定的文件(File)進行殺毒。該殺毒軟件還可以根據各類文件的特點,為不同類型的文件提供不同的殺毒方式,例如圖像文件(ImageFile)和文本文件(TextFile)的殺毒方式就有所差異。現需要提供該殺毒軟件的整體框架設計方案。
在介紹Sunny公司開發人員提出的初始解決方案之前,我們先來分析一下操作系統中的文件目錄結構,例如在Windows操作系統中,存在如圖11-1所示目錄結構:

圖11-1 Windows目錄結構
圖11-1可以簡化為如圖11-2所示樹形目錄結構:

圖11-2 樹形目錄結構示意圖
我們可以看出,在圖11-2中包含文件(灰色節點)和文件夾(白色節點)兩類不同的元素,其中在文件夾中可以包含文件,還可以繼續包含子文件夾,但是在文件中不能再包含子文件或者子文件夾。在此,我們可以稱文件夾為容器(Container),而不同類型的各種文件是其成員,也稱為葉子(Leaf),一個文件夾也可以作為另一個更大的文件夾的成員。如果我們現在要對某一個文件夾進行操作,如查找文件,那么需要對指定的文件夾進行遍歷,如果存在子文件夾則打開其子文件夾繼續遍歷,如果是文件則判斷之后返回查找結果。
Sunny軟件公司的開發人員通過分析,決定使用面向對象的方式來實現對文件和文件夾的操作,定義了如下圖像文件類ImageFile、文本文件類TextFile和文件夾類Folder:
```
//為了突出核心框架代碼,我們對殺毒過程的實現進行了大量簡化
import java.util.*;
//圖像文件類
class ImageFile {
private String name;
public ImageFile(String name) {
this.name = name;
}
public void killVirus() {
//簡化代碼,模擬殺毒
System.out.println("----對圖像文件'" + name + "'進行殺毒");
}
}
//文本文件類
class TextFile {
private String name;
public TextFile(String name) {
this.name = name;
}
public void killVirus() {
//簡化代碼,模擬殺毒
System.out.println("----對文本文件'" + name + "'進行殺毒");
}
}
//文件夾類
class Folder {
private String name;
//定義集合folderList,用于存儲Folder類型的成員
private ArrayList<Folder> folderList = new ArrayList<Folder>();
//定義集合imageList,用于存儲ImageFile類型的成員
private ArrayList<ImageFile> imageList = new ArrayList<ImageFile>();
//定義集合textList,用于存儲TextFile類型的成員
private ArrayList<TextFile> textList = new ArrayList<TextFile>();
public Folder(String name) {
this.name = name;
}
//增加新的Folder類型的成員
public void addFolder(Folder f) {
folderList.add(f);
}
//增加新的ImageFile類型的成員
public void addImageFile(ImageFile image) {
imageList.add(image);
}
//增加新的TextFile類型的成員
public void addTextFile(TextFile text) {
textList.add(text);
}
//需提供三個不同的方法removeFolder()、removeImageFile()和removeTextFile()來刪除成員,代碼省略
//需提供三個不同的方法getChildFolder(int i)、getChildImageFile(int i)和getChildTextFile(int i)來獲取成員,代碼省略
public void killVirus() {
System.out.println("****對文件夾'" + name + "'進行殺毒"); //模擬殺毒
//如果是Folder類型的成員,遞歸調用Folder的killVirus()方法
for(Object obj : folderList) {
((Folder)obj).killVirus();
}
//如果是ImageFile類型的成員,調用ImageFile的killVirus()方法
for(Object obj : imageList) {
((ImageFile)obj).killVirus();
}
//如果是TextFile類型的成員,調用TextFile的killVirus()方法
for(Object obj : textList) {
((TextFile)obj).killVirus();
}
}
}
```
編寫如下客戶端測試代碼進行測試:
```
class Client {
public static void main(String args[]) {
Folder folder1,folder2,folder3;
folder1 = new Folder("Sunny的資料");
folder2 = new Folder("圖像文件");
folder3 = new Folder("文本文件");
ImageFile image1,image2;
image1 = new ImageFile("小龍女.jpg");
image2 = new ImageFile("張無忌.gif");
TextFile text1,text2;
text1 = new TextFile("九陰真經.txt");
text2 = new TextFile("葵花寶典.doc");
folder2.addImageFile(image1);
folder2.addImageFile(image2);
folder3.addTextFile(text1);
folder3.addTextFile(text2);
folder1.addFolder(folder2);
folder1.addFolder(folder3);
folder1.killVirus();
}
}
```
編譯并運行程序,輸出結果如下:
```
****對文件夾'Sunny的資料'進行殺毒
****對文件夾'圖像文件'進行殺毒
----對圖像文件'小龍女.jpg'進行殺毒
----對圖像文件'張無忌.gif'進行殺毒
****對文件夾'文本文件'進行殺毒
----對文本文件'九陰真經.txt'進行殺毒
----對文本文件'葵花寶典.doc'進行殺毒
```
Sunny公司開發人員“成功”實現了殺毒軟件的框架設計,但通過仔細分析,發現該設計方案存在如下問題:
(1) 文件夾類Folder的設計和實現都非常復雜,需要定義多個集合存儲不同類型的成員,而且需要針對不同的成員提供增加、刪除和獲取等管理和訪問成員的方法,存在大量的冗余代碼,系統維護較為困難;
(2) 由于系統沒有提供抽象層,客戶端代碼必須有區別地對待充當容器的文件夾Folder和充當葉子的ImageFile和TextFile,無法統一對它們進行處理;
(3) 系統的靈活性和可擴展性差,如果需要增加新的類型的葉子和容器都需要對原有代碼進行修改,例如如果需要在系統中增加一種新類型的視頻文件VideoFile,則必須修改Folder類的源代碼,否則無法在文件夾中添加視頻文件。
面對以上問題,Sunny軟件公司的開發人員該如何來解決?這就需要用到本章將要介紹的組合模式,組合模式為處理樹形結構提供了一種較為完美的解決方案,它描述了如何將容器和葉子進行遞歸組合,使得用戶在使用時無須對它們進行區分,可以一致地對待容器和葉子。
- Introduction
- 基礎知識
- 設計模式概述
- 從招式與內功談起——設計模式概述(一)
- 從招式與內功談起——設計模式概述(二)
- 從招式與內功談起——設計模式概述(三)
- 面向對象設計原則
- 面向對象設計原則之單一職責原則
- 面向對象設計原則之開閉原則
- 面向對象設計原則之里氏代換原則
- 面向對象設計原則之依賴倒轉原則
- 面向對象設計原則之接口隔離原則
- 面向對象設計原則之合成復用原則
- 面向對象設計原則之迪米特法則
- 六個創建型模式
- 簡單工廠模式-Simple Factory Pattern
- 工廠三兄弟之簡單工廠模式(一)
- 工廠三兄弟之簡單工廠模式(二)
- 工廠三兄弟之簡單工廠模式(三)
- 工廠三兄弟之簡單工廠模式(四)
- 工廠方法模式-Factory Method Pattern
- 工廠三兄弟之工廠方法模式(一)
- 工廠三兄弟之工廠方法模式(二)
- 工廠三兄弟之工廠方法模式(三)
- 工廠三兄弟之工廠方法模式(四)
- 抽象工廠模式-Abstract Factory Pattern
- 工廠三兄弟之抽象工廠模式(一)
- 工廠三兄弟之抽象工廠模式(二)
- 工廠三兄弟之抽象工廠模式(三)
- 工廠三兄弟之抽象工廠模式(四)
- 工廠三兄弟之抽象工廠模式(五)
- 單例模式-Singleton Pattern
- 確保對象的唯一性——單例模式 (一)
- 確保對象的唯一性——單例模式 (二)
- 確保對象的唯一性——單例模式 (三)
- 確保對象的唯一性——單例模式 (四)
- 確保對象的唯一性——單例模式 (五)
- 原型模式-Prototype Pattern
- 對象的克隆——原型模式(一)
- 對象的克隆——原型模式(二)
- 對象的克隆——原型模式(三)
- 對象的克隆——原型模式(四)
- 建造者模式-Builder Pattern
- 復雜對象的組裝與創建——建造者模式(一)
- 復雜對象的組裝與創建——建造者模式(二)
- 復雜對象的組裝與創建——建造者模式(三)
- 七個結構型模式
- 適配器模式-Adapter Pattern
- 不兼容結構的協調——適配器模式(一)
- 不兼容結構的協調——適配器模式(二)
- 不兼容結構的協調——適配器模式(三)
- 不兼容結構的協調——適配器模式(四)
- 橋接模式-Bridge Pattern
- 處理多維度變化——橋接模式(一)
- 處理多維度變化——橋接模式(二)
- 處理多維度變化——橋接模式(三)
- 處理多維度變化——橋接模式(四)
- 組合模式-Composite Pattern
- 樹形結構的處理——組合模式(一)
- 樹形結構的處理——組合模式(二)
- 樹形結構的處理——組合模式(三)
- 樹形結構的處理——組合模式(四)
- 樹形結構的處理——組合模式(五)
- 裝飾模式-Decorator Pattern
- 擴展系統功能——裝飾模式(一)
- 擴展系統功能——裝飾模式(二)
- 擴展系統功能——裝飾模式(三)
- 擴展系統功能——裝飾模式(四)
- 外觀模式-Facade Pattern
- 深入淺出外觀模式(一)
- 深入淺出外觀模式(二)
- 深入淺出外觀模式(三)
- 享元模式-Flyweight Pattern
- 實現對象的復用——享元模式(一)
- 實現對象的復用——享元模式(二)
- 實現對象的復用——享元模式(三)
- 實現對象的復用——享元模式(四)
- 實現對象的復用——享元模式(五)
- 代理模式-Proxy Pattern
- 設計模式之代理模式(一)
- 設計模式之代理模式(二)
- 設計模式之代理模式(三)
- 設計模式之代理模式(四)
- 十一個行為型模式
- 職責鏈模式-Chain of Responsibility Pattern
- 請求的鏈式處理——職責鏈模式(一)
- 請求的鏈式處理——職責鏈模式(二)
- 請求的鏈式處理——職責鏈模式(三)
- 請求的鏈式處理——職責鏈模式(四)
- 命令模式-Command Pattern
- 請求發送者與接收者解耦——命令模式(一)
- 請求發送者與接收者解耦——命令模式(二)
- 請求發送者與接收者解耦——命令模式(三)
- 請求發送者與接收者解耦——命令模式(四)
- 請求發送者與接收者解耦——命令模式(五)
- 請求發送者與接收者解耦——命令模式(六)
- 解釋器模式-Interpreter Pattern
- 自定義語言的實現——解釋器模式(一)
- 自定義語言的實現——解釋器模式(二)
- 自定義語言的實現——解釋器模式(三)
- 自定義語言的實現——解釋器模式(四)
- 自定義語言的實現——解釋器模式(五)
- 自定義語言的實現——解釋器模式(六)
- 迭代器模式-Iterator Pattern
- 遍歷聚合對象中的元素——迭代器模式(一)
- 遍歷聚合對象中的元素——迭代器模式(二)
- 遍歷聚合對象中的元素——迭代器模式(三)
- 遍歷聚合對象中的元素——迭代器模式(四)
- 遍歷聚合對象中的元素——迭代器模式(五)
- 遍歷聚合對象中的元素——迭代器模式(六)
- 中介者模式-Mediator Pattern
- 協調多個對象之間的交互——中介者模式(一)
- 協調多個對象之間的交互——中介者模式(二)
- 協調多個對象之間的交互——中介者模式(三)
- 協調多個對象之間的交互——中介者模式(四)
- 協調多個對象之間的交互——中介者模式(五)
- 備忘錄模式-Memento Pattern
- 撤銷功能的實現——備忘錄模式(一)
- 撤銷功能的實現——備忘錄模式(二)
- 撤銷功能的實現——備忘錄模式(三)
- 撤銷功能的實現——備忘錄模式(四)
- 撤銷功能的實現——備忘錄模式(五)
- 觀察者模式-Observer Pattern
- 對象間的聯動——觀察者模式(一)
- 對象間的聯動——觀察者模式(二)
- 對象間的聯動——觀察者模式(三)
- 對象間的聯動——觀察者模式(四)
- 對象間的聯動——觀察者模式(五)
- 對象間的聯動——觀察者模式(六)
- 狀態模式-State Pattern
- 處理對象的多種狀態及其相互轉換——狀態模式(一)
- 處理對象的多種狀態及其相互轉換——狀態模式(二)
- 處理對象的多種狀態及其相互轉換——狀態模式(三)
- 處理對象的多種狀態及其相互轉換——狀態模式(四)
- 處理對象的多種狀態及其相互轉換——狀態模式(五)
- 處理對象的多種狀態及其相互轉換——狀態模式(六)
- 策略模式-Strategy Pattern
- 算法的封裝與切換——策略模式(一)
- 算法的封裝與切換——策略模式(二)
- 算法的封裝與切換——策略模式(三)
- 算法的封裝與切換——策略模式(四)
- 模板方法模式-Template Method Pattern
- 模板方法模式深度解析(一)
- 模板方法模式深度解析(二)
- 模板方法模式深度解析(三)
- 訪問者模式-Visitor Pattern
- 操作復雜對象結構——訪問者模式(一)
- 操作復雜對象結構——訪問者模式(二)
- 操作復雜對象結構——訪問者模式(三)
- 操作復雜對象結構——訪問者模式(四)
- 設計模式趣味學習(復習)
- 設計模式與足球(一)
- 設計模式與足球(二)
- 設計模式與足球(三)
- 設計模式與足球(四)
- 設計模式綜合應用實例
- 多人聯機射擊游戲
- 多人聯機射擊游戲中的設計模式應用(一)
- 多人聯機射擊游戲中的設計模式應用(二)
- 數據庫同步系統
- 設計模式綜合實例分析之數據庫同步系統(一)
- 設計模式綜合實例分析之數據庫同步系統(二)
- 設計模式綜合實例分析之數據庫同步系統(三)