设计模式(十一):从文Finder中认识组合模式(Composite Pattern)
上一篇博客中我們從從電影院中認識了"迭代器模式"(Iterator Pattern),今天我們就從文件系統(tǒng)中來認識一下“組合模式”(Composite Pattern)。說到組合模式,在此我想聊一下在類圖中有組合與聚合的關(guān)系,這兩者都是整體和部分的關(guān)系,只是整體與部分的依賴度不同。在聚合關(guān)系中,整體強烈依賴于部分,而部分脫離于整體將沒有存在的意義,比如你身上的器官與你的關(guān)系就是聚合關(guān)系。而對于組合關(guān)系來說整體與部分的依賴就相對于小一些,離開彼此也是可以獨立生存的,比如員工與公司的關(guān)系,就是組合關(guān)系。
言歸正傳,今天我們來介紹一下“組合模式”。下方就是組合模式的定義:
組合模式:允許你將對象組合成樹形結(jié)構(gòu)來表現(xiàn)“整體/部分”層次結(jié)構(gòu)。組合能讓客戶以一致的方式處理個別對象已經(jīng)對象組合
組合模式也就是將多個獨立的個體組合到一塊,不過組合時是有層級關(guān)系的,而這些層級關(guān)系是“樹”形的關(guān)系。典型的樹狀層級關(guān)系就是我們的文件系統(tǒng),下方截圖就是我們資源管理器的一個文件層級的截圖??梢悦鞔_的看出下方是樹狀的層級關(guān)系。今天我們的任務就是使用“組合模式”模擬下方的文件結(jié)構(gòu)。從下方的截圖中我們可以分析出文件總體上可以分為兩種類型,一個是文件夾,在一個就是真正有內(nèi)容的文件。文件夾是一種容器,它不僅可以存儲文件還可以存儲文件夾。文件夾可以存儲文件以及其他文件夾,這一特性就決定文件系統(tǒng)是一個樹形結(jié)構(gòu)。
? ? ? ?
?
一、模擬“文件系統(tǒng)”實現(xiàn)的類圖設計
依舊是老套路,我們要使用代碼結(jié)合“組合模式”來模仿上面截圖中的文件結(jié)構(gòu),首先我們先來設計類圖,然后在根據(jù)我們設計的類圖來給出代碼實現(xiàn)。上面我們已經(jīng)提到過文件夾就是可以存儲其他文件夾和文件的容器,所以在我們設計實現(xiàn)是打算使用Dictionary(字典)來實現(xiàn)這一容器的特性,至于如何去實現(xiàn)下方會給出具體的實現(xiàn)方式。下方的類圖就是我們要實現(xiàn)的“文件系統(tǒng)”的類圖,當然我們是模擬的,盡量的簡化了一些操作。下方也使用了組合模式,Folder類就是組合文件夾與文件的地方,稍后會給出具體的說明。
首先我們來介紹下方黃色框中的文件類型協(xié)議與該協(xié)議的延展。FileType是我們所有文件的協(xié)議,無論是文件夾還是具體文件都遵循該協(xié)議,該協(xié)議中給出了文件以及文件夾的必要操作。在該協(xié)議的默認延展中給出了協(xié)議中那些只需要文件夾實現(xiàn)而具體文件不需要實現(xiàn)的方法,如addFile()、deleteFile()方法,只有文件夾容器才會有這些方法。該協(xié)議的具體呢絨如下類圖中黃框中的內(nèi)容所示。
然后是紅框中的部分,紅框中是我們文件夾的實現(xiàn),也是我們組合模式的核心模塊。經(jīng)過觀察Folder(文件夾)類,我們不難發(fā)現(xiàn)Folder不僅僅遵循了FileType接口,還依賴于FileType接口。因為Folder是文件的一種類型,所以要遵循FileType接口。同時Folder是文件的容器,可以存放所有的文件和文件夾(也就是遵循FileType接口的所有類),所以Folder依賴于FileType接口。這個特性決定了組合模式有著樹形結(jié)構(gòu)。
最后是綠框中的部分,該部分的代碼比較單純。綠框中是具體文件的類。該模塊有一個基類,也就是BaseFile。所有的具體文件都繼承自BaseFile,因為BaseFile也是文件的一種所以也需要遵循FileType協(xié)議。因為具體文件不是容器,不需要實現(xiàn)addFile()等容器使用到的方法。因為具體文件遵循了FileType協(xié)議,而Folder依賴于FileType協(xié)議,所以Folder可以存儲具體文件。整體的類圖如下所示:
?
?
?
二、“文件系統(tǒng)”的代碼實現(xiàn)
有了上面的類圖,再給出相應的代碼實現(xiàn)就容易的多了。接下來我們就根據(jù)上面的類圖,給出相應的Swift代碼實現(xiàn)。首先我們會給出FileType協(xié)議以及其延展的實現(xiàn),具體代碼片段如下所示。getFileName()方法用戶獲取文件名,addFile(file)用于文件夾添加文件,deleteFile(file)用于文件夾刪除文件,display()用于打印文件名。FileType延展中給出了具體文件不需要實現(xiàn)的方法,所以在延展中給出了一個默認的實現(xiàn),類似于抽象類中的方法實現(xiàn)。因為在協(xié)議延展中給出了方法的默認實現(xiàn),所以在文件類中的可以不給出協(xié)議延展中的方法。FileType與其延展的代碼段如下所示。
? ??
?
實現(xiàn)完相關(guān)的接口和擴展后就開始實現(xiàn)我們的具體類了,接下來我們將要給出組合模式的核心類Folder(容器類)。下方的Folder就是我們用代碼實現(xiàn)的文件夾,Folder遵循了FileType接口,并給出了相應方法的具體實現(xiàn)。在Folder中我們要注意一下files屬性,該屬性就是組合的聚集地。我們可以看出files的類型是一個字典,字典的key是String類型,而字典的Value是FileType類型。也就是說files中可以存儲遵循FileType協(xié)議的所有類,也就是files中可以存儲文件和文件夾?!敖M合模式”在此處的提現(xiàn)就是文件以及文件夾在一塊進行組合會生成一個新的文件夾。
下方還需要注意的就是Folder中的display()方法。該方法是遍歷files數(shù)組,然后取出其中的文件或者文件夾對象,然后調(diào)用這些對象的display()方法。這樣就會輸出當前文件夾下所有的文件的名稱。Folder文件夾類的具體實現(xiàn)方式如下所示:
? ?
?
上面給出了文件夾的實現(xiàn),接著我們要實現(xiàn)另一種文件類型,就是具體的文件了。在實現(xiàn)具體文件時,我們定義了一個具體文件的基類,就是BaseFile。當然BaseFile也遵循與FileType協(xié)議,這就是我們面向接口編程。在BaseFile基類中我們給出了所有文件所共有的方法,比如getFileName()和display()方法。接著我們又實現(xiàn)了兩個特定的文件類型,一個Swift源文件SwiftFile,另一個就是Objective-C源文件ObjCFile。這兩個具體的文件都繼承自BaseFile類。具體代碼實現(xiàn)如下所示:
? ??
?
三、測試用例
接下來就到了測試用例的部分了,也就是上面類圖中的Client的部分。Client就是該文件系統(tǒng)的使用者,從類圖中我們可以看出來,Client依賴于FileType接口而不依賴于具體實現(xiàn)。因為我們是在Xcode中的Playground中做的測試,所以我們就沒有給出具體的Client類。但是下方代碼就等同于Client類中的代碼。下方就是我們的測試用例我們構(gòu)建了本文開頭的文件目錄結(jié)構(gòu),并輸出了文件夾下所有文件的名稱。測試用例與輸出結(jié)果如下所示:
? ??
至此我們的“組合模式”的一個完整示例就執(zhí)行完了。
同樣今天的Demo也會在github上進行分享,分享地址為:https://github.com/lizelu/DesignPatterns-Swift
?
轉(zhuǎn)載于:https://www.cnblogs.com/ludashi/p/5439128.html
總結(jié)
以上是生活随笔為你收集整理的设计模式(十一):从文Finder中认识组合模式(Composite Pattern)的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 常用快捷键归纳
- 下一篇: 设计模式之禅读书笔记