Java設(shè)計(jì)模式:組合模式
在本講,我們來(lái)學(xué)習(xí)一下結(jié)構(gòu)型模式里面的第六個(gè)設(shè)計(jì)模式,即組合模式。
概述
在學(xué)習(xí)組合模式之前,我們先來(lái)看下面這張圖。
對(duì)于以上這張圖大家應(yīng)該很熟悉,我們可以將其看作是一個(gè)文件系統(tǒng),其實(shí)說(shuō)到底它就是Windows系統(tǒng)里面的一個(gè)目錄結(jié)構(gòu),只不過(guò)對(duì)于Windows中的文件系統(tǒng)而言,它里面包含有C盤、D盤、E盤等等盤符,而這里我們只是以它里面的某一個(gè)盤符里面的目錄結(jié)構(gòu)為例來(lái)進(jìn)行了一個(gè)描述。
對(duì)于這樣的結(jié)構(gòu)我們稱之為樹(shù)形結(jié)構(gòu)。為啥叫樹(shù)形結(jié)構(gòu)呢?你看一下上圖中的左邊部分,最上面是不是有一個(gè)WINDOWS目錄啊,而該WINDOWS目錄下面又有很多的子目錄或者子文件,這樣,我們就能將其描述成上圖右邊部分的樹(shù)形結(jié)構(gòu)了,它是不是很像一棵倒著的樹(shù)??!既然是一棵樹(shù),那么它就只有一個(gè)樹(shù)根了,很明顯,這個(gè)樹(shù)根就是最頂層的WINDOWS目錄,在該目錄下,自然就會(huì)生成許多的子文件或者子文件夾了,而如果要是子文件夾的話,那么它下面又可以有許多的子文件或者子文件夾了,以此類推,一棵參天大樹(shù)就長(zhǎng)成了。
對(duì)于這樣一個(gè)文件系統(tǒng)而言,有幾個(gè)概念大家需要知道一下,文件夾或者文件我們都可稱之為節(jié)點(diǎn),但是一般來(lái)說(shuō),我們稱文件為葉子節(jié)點(diǎn),稱文件夾為樹(shù)枝節(jié)點(diǎn),這是因?yàn)闃?shù)枝還可以再去生成子樹(shù)枝或者子葉子。
在這樣一個(gè)樹(shù)形結(jié)構(gòu)中,我們可以通過(guò)調(diào)用某個(gè)方法來(lái)遍歷整棵樹(shù),當(dāng)我們找到某個(gè)葉子節(jié)點(diǎn)后,就可以對(duì)葉子節(jié)點(diǎn)進(jìn)行相關(guān)的操作了。因此,我們不妨將這顆樹(shù)理解成一個(gè)大的容器,容器里面包含有很多的成員對(duì)象(其實(shí)就是節(jié)點(diǎn)對(duì)象),這些成員對(duì)象既可以是容器對(duì)象(即文件夾,當(dāng)然你也可以把它稱作是樹(shù)枝對(duì)象)也可以是葉子對(duì)象(即文件)。但是由于容器對(duì)象和葉子對(duì)象在功能上面有所區(qū)別(區(qū)別是很明顯的,葉子對(duì)象,即文件,可以讀寫數(shù)據(jù),但是它下面不可能再有子文件或者子文件夾了;而容器對(duì)象,即文件夾,它下面是可以再有子文件或者子文件的,但是它不能進(jìn)行數(shù)據(jù)的一個(gè)讀寫操作),使得我們?cè)谑褂玫倪^(guò)程中必須要區(qū)分容器對(duì)象和葉子對(duì)象,但是這樣一來(lái)就會(huì)給客戶帶來(lái)不必要的麻煩,對(duì)于客戶來(lái)說(shuō)的話,他始終是希望能夠一致的對(duì)待容器對(duì)象和葉子對(duì)象。也就是說(shuō),對(duì)于客戶而言,不管是文件夾還是文件,他都希望一致的去對(duì)待它們,即把它們都當(dāng)作同樣的一個(gè)對(duì)象來(lái)進(jìn)行處理。
至此,我們就認(rèn)識(shí)了一下以上樹(shù)形結(jié)構(gòu),并且咱們還知道了該樹(shù)形結(jié)構(gòu)所存在的一個(gè)問(wèn)題。那如何解決該問(wèn)題呢?很明顯,就要用到組合模式了,因?yàn)楸疚闹v的就是組合模式嘛!
那什么是組合模式呢?下面我們來(lái)看看它的概念。
組合模式又名部分整體模式(啥又叫部分整體模式呢?上面不是說(shuō)過(guò)嘛,我們可以將一棵樹(shù)理解成一個(gè)大的容器,對(duì)于該容器而言,它就是整體;然后它下面不是又有子文件或者子文件夾嘛,這些子文件或者子文件夾我們就稱之為部分,當(dāng)然,部分下面是不是還可以再分出部分來(lái)?。。?,是用于把一組相似的對(duì)象當(dāng)作一個(gè)單一的對(duì)象。組合模式依據(jù)樹(shù)形結(jié)構(gòu)來(lái)組合對(duì)象,用來(lái)表示部分以及整體層次,這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它創(chuàng)建了對(duì)象組的樹(shù)形結(jié)構(gòu)。
看完以上組合模式的概念之后,相信大家就能知道應(yīng)該要使用組合模式來(lái)解決以上樹(shù)形結(jié)構(gòu)所存在的問(wèn)題了,因?yàn)閷?duì)于客戶而言,他就能一致的去對(duì)待容器對(duì)象和葉子對(duì)象了,這樣,他使用起來(lái)也會(huì)變得更加簡(jiǎn)單。
結(jié)構(gòu)
組合模式主要包含有三種角色:
- 抽象根節(jié)點(diǎn)(Component):定義系統(tǒng)各層次對(duì)象具有的共有方法和屬性,可以預(yù)先定義一些默認(rèn)行為和屬性。
怎么來(lái)理解抽象根節(jié)點(diǎn)呢?還是通過(guò)上圖來(lái)理解,不管是文件夾還是文件,我們都可以向上抽取,抽取出一個(gè)抽象類,而在這個(gè)抽象類里面,我們就可以去定義文件和文件夾中的共有行為和屬性了。也就是說(shuō),正是因?yàn)榭蛻羲胍恢碌娜?duì)待容器對(duì)象和葉子對(duì)象,所以他就可以定義出這么一個(gè)公共的抽象類了
- 樹(shù)枝節(jié)點(diǎn)(Composite):定義樹(shù)枝節(jié)點(diǎn)的行為,即存儲(chǔ)子節(jié)點(diǎn),組合樹(shù)枝節(jié)點(diǎn)和葉子節(jié)點(diǎn)形成一個(gè)樹(shù)形結(jié)構(gòu)。
- 葉子節(jié)點(diǎn)(Leaf):葉子節(jié)點(diǎn)對(duì)象,其下再無(wú)分支,是系統(tǒng)層次遍歷的最小單位。
組合模式案例
接下來(lái),我們就通過(guò)一個(gè)案例再來(lái)理解一下組合模式,這個(gè)案例就是軟件菜單。
分析
先來(lái)看一下下面這張圖。
相信大家還是比較熟悉以上這張圖的,因?yàn)槲覀冊(cè)谠L問(wèn)別的一些管理系統(tǒng)時(shí),經(jīng)??梢钥吹筋愃频牟藛巍R粋€(gè)菜單可以包含菜單項(xiàng)(菜單項(xiàng)是指不再包含其他內(nèi)容的菜單條目),也可以包含帶有其他菜單項(xiàng)的菜單,就拿以上系統(tǒng)管理菜單來(lái)說(shuō),它下面有三個(gè)子菜單,分別是菜單管理、權(quán)限配置、角色管理,它們都是屬于菜單,因?yàn)樗鼈兿旅孢€可以有子菜單或者子菜單項(xiàng)。對(duì)于菜單管理來(lái)說(shuō),它下面有五個(gè)子菜單項(xiàng),分別是頁(yè)面訪問(wèn)、展開(kāi)菜單、編輯菜單、刪除菜單、新增菜單,注意了,它們都是菜單項(xiàng),下面不可能再有子菜單或者子菜單項(xiàng)了,故它們都是屬于葉子節(jié)點(diǎn);而系統(tǒng)管理、菜單管理、權(quán)限配置、角色管理,它們均屬于樹(shù)枝節(jié)點(diǎn),并且系統(tǒng)管理從根本上來(lái)說(shuō),它是屬于根節(jié)點(diǎn)。因此,使用組合模式來(lái)描述以上菜單就很恰當(dāng)了。
這樣,我們的需求就是針對(duì)一個(gè)菜單,例如系統(tǒng)管理,打印出其包含的所有菜單以及菜單項(xiàng)的名稱。
需求明確之后,接下來(lái)我們就要編寫代碼解決該需求了。首先,對(duì)于該需求,我們先設(shè)計(jì)出一個(gè)如下的類圖。
總結(jié)
本篇文章就到這里了,希望能夠給你帶來(lái)幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!
相關(guān)文章
springboot升級(jí)到j(luò)dk21最新教程(2023年)
你還在使用jdk8?快來(lái)看看最新出爐的SpringBoot+jdk21如何使用,下面這篇文章主要給大家介紹了關(guān)于springboot升級(jí)到j(luò)dk21的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-10-10Spring中的EventListenerMethodProcessor組件詳解
這篇文章主要介紹了Spring中的EventListenerMethodProcessor組件詳解,EventListenerMethodProcessor 是 Spring 事件機(jī)制中非常重要的一個(gè)組件,它管理了一組EventListenerFactory組件,用來(lái)將應(yīng)用中每個(gè)使用@EventListener注解定義的事件監(jiān)聽(tīng),需要的朋友可以參考下2023-12-12springboot使用hibernate validation對(duì)參數(shù)校驗(yàn)的實(shí)現(xiàn)方法
這篇文章主要介紹了spring-boot 使用hibernate validation對(duì)參數(shù)進(jìn)行優(yōu)雅的校驗(yàn),本文通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-12-12Mybatis基于注解形式的sql語(yǔ)句生成實(shí)例代碼
這篇文章主要介紹了 Mybatis基于注解形式的sql語(yǔ)句生成實(shí)例代碼,需要的朋友可以參考下2017-09-09通過(guò)Java?Reflection實(shí)現(xiàn)編譯時(shí)注解正確處理方法
Java注解是一種標(biāo)記在JDK5及以后的版本中引入,用于Java語(yǔ)言中向程序添加元數(shù)據(jù)的方法,這篇文章主要介紹了通過(guò)Java?Reflection實(shí)現(xiàn)編譯時(shí)注解處理方法,需要的朋友可以參考下2023-06-06Java中的FileInputStream是否需要close問(wèn)題
這篇文章主要介紹了Java中的FileInputStream是否需要close問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-12-12Spring?Security中使用authorizeRequests遇到的問(wèn)題小結(jié)
Spring?是非常流行和成功的?Java?應(yīng)用開(kāi)發(fā)框架,Spring?Security?正是?Spring?家族中的成員,這篇文章主要介紹了Spring?Security中使用authorizeRequests遇到的問(wèn)題,需要的朋友可以參考下2023-02-02探討Java中最常見(jiàn)的十道面試題(超經(jīng)典)
本篇文章是對(duì)Java中最常見(jiàn)的十道面試題進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-07-07