公號:碼農充電站pro
主頁:https://codeshellme.github.io
本篇來介紹組合模式(Composite Design Pattern)。
1,組合模式
組合模式可以將物件組合成樹形結構來表示“整體-部分”的層次結構,使得客戶可以用一致的方式處理個別物件和物件組合。
如果物件之間呈樹形結構,是一種部分與整體的關係,這種情況都比較適合用組合模式。
組合模式構建的樹狀關係如下所示:
組合模式使得我們構建這種樹狀關係變得極為簡單。aComposite 是組合物件,aLeaf 是個體物件。組合物件中可以巢狀組合物件和個體物件,個體物件中不能再包含其它物件。
因為組合物件中可以再次巢狀組合物件,所以組合模式也是一種遞迴關係。
組合模式的類圖如下:
從類圖中可以看到,Component 為所有的物件提供了統一的介面。組合物件中有 add
和 remove
操作,說明組合物件中可以新增和刪除組合物件與個體物件。
注意 Leaf 節點中只有 operation 操作,因為 Leaf 節點不能再巢狀其它節點。
組合物件和個體物件中都有 operation
操作,使得我們能夠把相同的操作應用在組合物件和個別物件上。
2,組合模式示例
下面舉個例子,來看下如何使用組合模式。
我們已經知道,組合模式非常適合表示樹形結構,而 Linux 目錄結構就是一個樹形結構。下面就用組合模式來構建目錄結構。
我們知道目錄中即可包含目錄,也可包含檔案。根據組合模式的類圖,可設計出下面的 Linux 檔案系統類圖:
檔案系統可以包括檔案和目錄,目錄中可以巢狀目錄和檔案,而檔案中不能再巢狀其它東西。所以,File 類中沒有 add
和 remove
方法。
首先建立 FileSystem 抽象類:
abstract class FileSystem {
protected String path;
public abstract void printFile();
}
printFile
方法用於輸出檔名。
再建立 File 類:
class File extends FileSystem {
public File(String path) {
this.path = path;
}
public void printFile() {
System.out.println(path);
}
}
File 類繼承了 FileSystem, 因為 File 類本身就是檔案,所以它的 printFile
非常簡單。
再建立 Directory 類:
class Directory extends FileSystem {
private List<FileSystem> nodes; // 用於儲存節點
public Directory(String path) {
this.path = path;
this.nodes = new ArrayList<>();
}
public void printFile() {
System.out.println(path);
// 遞迴輸出目錄和檔案
for (FileSystem node: nodes) {
node.printFile();
}
}
public void addNode(FileSystem node) {
nodes.add(node);
}
public void removeNode(FileSystem node) {
nodes.remove(node);
}
}
注意區分 File 類和 Directory 類的不同。
下面來測試程式碼,假設我們要構建這樣的目錄結構:
test/
├── a
├── b
│ ├── 1.txt
│ └── d
│ └── 2.txt
└── c
└── 3.txt
首先建立檔案節點和目錄節點:
// 建立檔案節點
File txt1 = new File("test/b/1.txt");
File txt2 = new File("test/b/d/2.txt");
File txt3 = new File("test/c/3.txt");
// 建立目錄節點
Directory test = new Directory("test/");
Directory a = new Directory("test/a/");
Directory b = new Directory("test/b/");
Directory c = new Directory("test/c/");
Directory d = new Directory("test/b/d/");
構建目錄結構:
// 構造目錄結構
test.addNode(a);
test.addNode(b);
test.addNode(c);
b.addNode(txt1);
b.addNode(d);
c.addNode(txt3);
d.addNode(txt2);
輸出 test 目錄:
test.printFile();
結果如下:
test/
test/a/
test/b/
test/b/1.txt
test/b/d/
test/b/d/2.txt
test/c/
test/c/3.txt
輸出 b 目錄:
b.printFile();
結果如下:
test/b/
test/b/1.txt
test/b/d/
test/b/d/2.txt
刪除 b 目錄後,在輸出 test 目錄:
test.removeNode(b);
test.printFile();
結果如下:
test/
test/a/
test/c/
test/c/3.txt
通過測試結果可以看到,我們構建的目錄結構是沒有問題的。
我將完整的程式碼放在了這裡,供大家參考。
3,總結
組合模式將一組物件組織成樹形結構,物件分為個體物件和組合物件,組合物件中可以包含個體物件和組合物件。組合模式會以遞迴的方式來處理樹的節點。
使用組合模式的前提是,物件之間的關係要符合樹形結構的特點。組合模式使得處理樹形結構的物件關係變得非常簡單。
(本節完。)
推薦閱讀:
歡迎關注作者公眾號,獲取更多技術乾貨。