Java設(shè)計(jì)模式:組合模式
在本講,我們來學(xué)習(xí)一下結(jié)構(gòu)型模式里面的第六個設(shè)計(jì)模式,即組合模式。
概述
在學(xué)習(xí)組合模式之前,我們先來看下面這張圖。

對于以上這張圖大家應(yīng)該很熟悉,我們可以將其看作是一個文件系統(tǒng),其實(shí)說到底它就是Windows系統(tǒng)里面的一個目錄結(jié)構(gòu),只不過對于Windows中的文件系統(tǒng)而言,它里面包含有C盤、D盤、E盤等等盤符,而這里我們只是以它里面的某一個盤符里面的目錄結(jié)構(gòu)為例來進(jìn)行了一個描述。
對于這樣的結(jié)構(gòu)我們稱之為樹形結(jié)構(gòu)。為啥叫樹形結(jié)構(gòu)呢?你看一下上圖中的左邊部分,最上面是不是有一個WINDOWS目錄啊,而該WINDOWS目錄下面又有很多的子目錄或者子文件,這樣,我們就能將其描述成上圖右邊部分的樹形結(jié)構(gòu)了,它是不是很像一棵倒著的樹??!既然是一棵樹,那么它就只有一個樹根了,很明顯,這個樹根就是最頂層的WINDOWS目錄,在該目錄下,自然就會生成許多的子文件或者子文件夾了,而如果要是子文件夾的話,那么它下面又可以有許多的子文件或者子文件夾了,以此類推,一棵參天大樹就長成了。
對于這樣一個文件系統(tǒng)而言,有幾個概念大家需要知道一下,文件夾或者文件我們都可稱之為節(jié)點(diǎn),但是一般來說,我們稱文件為葉子節(jié)點(diǎn),稱文件夾為樹枝節(jié)點(diǎn),這是因?yàn)闃渲€可以再去生成子樹枝或者子葉子。
在這樣一個樹形結(jié)構(gòu)中,我們可以通過調(diào)用某個方法來遍歷整棵樹,當(dāng)我們找到某個葉子節(jié)點(diǎn)后,就可以對葉子節(jié)點(diǎn)進(jìn)行相關(guān)的操作了。因此,我們不妨將這顆樹理解成一個大的容器,容器里面包含有很多的成員對象(其實(shí)就是節(jié)點(diǎn)對象),這些成員對象既可以是容器對象(即文件夾,當(dāng)然你也可以把它稱作是樹枝對象)也可以是葉子對象(即文件)。但是由于容器對象和葉子對象在功能上面有所區(qū)別(區(qū)別是很明顯的,葉子對象,即文件,可以讀寫數(shù)據(jù),但是它下面不可能再有子文件或者子文件夾了;而容器對象,即文件夾,它下面是可以再有子文件或者子文件的,但是它不能進(jìn)行數(shù)據(jù)的一個讀寫操作),使得我們在使用的過程中必須要區(qū)分容器對象和葉子對象,但是這樣一來就會給客戶帶來不必要的麻煩,對于客戶來說的話,他始終是希望能夠一致的對待容器對象和葉子對象。也就是說,對于客戶而言,不管是文件夾還是文件,他都希望一致的去對待它們,即把它們都當(dāng)作同樣的一個對象來進(jìn)行處理。
至此,我們就認(rèn)識了一下以上樹形結(jié)構(gòu),并且咱們還知道了該樹形結(jié)構(gòu)所存在的一個問題。那如何解決該問題呢?很明顯,就要用到組合模式了,因?yàn)楸疚闹v的就是組合模式嘛!
那什么是組合模式呢?下面我們來看看它的概念。
組合模式又名部分整體模式(啥又叫部分整體模式呢?上面不是說過嘛,我們可以將一棵樹理解成一個大的容器,對于該容器而言,它就是整體;然后它下面不是又有子文件或者子文件夾嘛,這些子文件或者子文件夾我們就稱之為部分,當(dāng)然,部分下面是不是還可以再分出部分來?。。?,是用于把一組相似的對象當(dāng)作一個單一的對象。組合模式依據(jù)樹形結(jié)構(gòu)來組合對象,用來表示部分以及整體層次,這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它創(chuàng)建了對象組的樹形結(jié)構(gòu)。
看完以上組合模式的概念之后,相信大家就能知道應(yīng)該要使用組合模式來解決以上樹形結(jié)構(gòu)所存在的問題了,因?yàn)閷τ诳蛻舳?,他就能一致的去對待容器對象和葉子對象了,這樣,他使用起來也會變得更加簡單。
結(jié)構(gòu)
組合模式主要包含有三種角色:
- 抽象根節(jié)點(diǎn)(Component):定義系統(tǒng)各層次對象具有的共有方法和屬性,可以預(yù)先定義一些默認(rèn)行為和屬性。
怎么來理解抽象根節(jié)點(diǎn)呢?還是通過上圖來理解,不管是文件夾還是文件,我們都可以向上抽取,抽取出一個抽象類,而在這個抽象類里面,我們就可以去定義文件和文件夾中的共有行為和屬性了。也就是說,正是因?yàn)榭蛻羲胍恢碌娜Υ萜鲗ο蠛腿~子對象,所以他就可以定義出這么一個公共的抽象類了
- 樹枝節(jié)點(diǎn)(Composite):定義樹枝節(jié)點(diǎn)的行為,即存儲子節(jié)點(diǎn),組合樹枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)形成一個樹形結(jié)構(gòu)。
- 葉子節(jié)點(diǎn)(Leaf):葉子節(jié)點(diǎn)對象,其下再無分支,是系統(tǒng)層次遍歷的最小單位。
組合模式案例
接下來,我們就通過一個案例再來理解一下組合模式,這個案例就是軟件菜單。
分析
先來看一下下面這張圖。

相信大家還是比較熟悉以上這張圖的,因?yàn)槲覀冊谠L問別的一些管理系統(tǒng)時,經(jīng)??梢钥吹筋愃频牟藛?。一個菜單可以包含菜單項(xiàng)(菜單項(xiàng)是指不再包含其他內(nèi)容的菜單條目),也可以包含帶有其他菜單項(xiàng)的菜單,就拿以上系統(tǒng)管理菜單來說,它下面有三個子菜單,分別是菜單管理、權(quán)限配置、角色管理,它們都是屬于菜單,因?yàn)樗鼈兿旅孢€可以有子菜單或者子菜單項(xiàng)。對于菜單管理來說,它下面有五個子菜單項(xiàng),分別是頁面訪問、展開菜單、編輯菜單、刪除菜單、新增菜單,注意了,它們都是菜單項(xiàng),下面不可能再有子菜單或者子菜單項(xiàng)了,故它們都是屬于葉子節(jié)點(diǎn);而系統(tǒng)管理、菜單管理、權(quán)限配置、角色管理,它們均屬于樹枝節(jié)點(diǎn),并且系統(tǒng)管理從根本上來說,它是屬于根節(jié)點(diǎn)。因此,使用組合模式來描述以上菜單就很恰當(dāng)了。
這樣,我們的需求就是針對一個菜單,例如系統(tǒng)管理,打印出其包含的所有菜單以及菜單項(xiàng)的名稱。
需求明確之后,接下來我們就要編寫代碼解決該需求了。首先,對于該需求,我們先設(shè)計(jì)出一個如下的類圖。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
java中Hashtable和HashMap的區(qū)別分析
java中Hashtable和HashMap的區(qū)別分析,需要的朋友可以參考一下2013-04-04
springboot整合 xxl-job的項(xiàng)目實(shí)踐
XL-JOB是一個分布式任務(wù)調(diào)度平臺,用于解決分布式系統(tǒng)中的任務(wù)調(diào)度和管理問題,它包括調(diào)度中心、執(zhí)行器和Web管理控制臺,本文就來介紹一下springboot整合 xxl-job的項(xiàng)目實(shí)踐,感興趣的可以了解一下2024-09-09
Java中的Semaphore計(jì)數(shù)信號量詳細(xì)解析
這篇文章主要介紹了Java中的Semaphore計(jì)數(shù)信號量詳細(xì)解析,Semaphore?是一個計(jì)數(shù)信號量,必須由獲取它的線程釋放,常用于限制可以訪問某些資源的線程數(shù)量,例如通過?Semaphore?限流,需要的朋友可以參考下2023-11-11
淺談Java實(shí)現(xiàn)分布式事務(wù)的三種方案
現(xiàn)在互聯(lián)網(wǎng)下,分布式和微服務(wù)橫行,難免會遇到分布式下的事務(wù)問題,當(dāng)然微服務(wù)下可能沒有分布式事務(wù),但是很多場景是需要分布式事務(wù)的。下面就來介紹下什么是分布式事務(wù)和分布式事務(wù)的解決方案2021-06-06
springboot @Controller和@RestController的區(qū)別及應(yīng)用詳解
這篇文章主要介紹了springboot @Controller和@RestController的區(qū)別及應(yīng)用,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-11-11

