Java設計模式:組合模式

在本講,我們來學習一下結構型模式裡面的第六個設計模式,即組合模式。

概述

在學習組合模式之前,我們先來看下面這張圖。

在這裡插入圖片描述

對於以上這張圖大傢應該很熟悉,我們可以將其看作是一個文件系統,其實說到底它就是Windows系統裡面的一個目錄結構,隻不過對於Windows中的文件系統而言,它裡面包含有C盤、D盤、E盤等等盤符,而這裡我們隻是以它裡面的某一個盤符裡面的目錄結構為例來進行瞭一個描述。

對於這樣的結構我們稱之為樹形結構。為啥叫樹形結構呢?你看一下上圖中的左邊部分,最上面是不是有一個WINDOWS目錄啊,而該WINDOWS目錄下面又有很多的子目錄或者子文件,這樣,我們就能將其描述成上圖右邊部分的樹形結構瞭,它是不是很像一棵倒著的樹啊!既然是一棵樹,那麼它就隻有一個樹根瞭,很明顯,這個樹根就是最頂層的WINDOWS目錄,在該目錄下,自然就會生成許多的子文件或者子文件夾瞭,而如果要是子文件夾的話,那麼它下面又可以有許多的子文件或者子文件夾瞭,以此類推,一棵參天大樹就長成瞭。

對於這樣一個文件系統而言,有幾個概念大傢需要知道一下,文件夾或者文件我們都可稱之為節點,但是一般來說,我們稱文件為葉子節點,稱文件夾為樹枝節點,這是因為樹枝還可以再去生成子樹枝或者子葉子。

在這樣一個樹形結構中,我們可以通過調用某個方法來遍歷整棵樹,當我們找到某個葉子節點後,就可以對葉子節點進行相關的操作瞭。因此,我們不妨將這顆樹理解成一個大的容器,容器裡面包含有很多的成員對象(其實就是節點對象),這些成員對象既可以是容器對象(即文件夾,當然你也可以把它稱作是樹枝對象)也可以是葉子對象(即文件)。但是由於容器對象和葉子對象在功能上面有所區別(區別是很明顯的,葉子對象,即文件,可以讀寫數據,但是它下面不可能再有子文件或者子文件夾瞭;而容器對象,即文件夾,它下面是可以再有子文件或者子文件的,但是它不能進行數據的一個讀寫操作),使得我們在使用的過程中必須要區分容器對象和葉子對象,但是這樣一來就會給客戶帶來不必要的麻煩,對於客戶來說的話,他始終是希望能夠一致的對待容器對象和葉子對象。也就是說,對於客戶而言,不管是文件夾還是文件,他都希望一致的去對待它們,即把它們都當作同樣的一個對象來進行處理。

至此,我們就認識瞭一下以上樹形結構,並且咱們還知道瞭該樹形結構所存在的一個問題。那如何解決該問題呢?很明顯,就要用到組合模式瞭,因為本文講的就是組合模式嘛!

那什麼是組合模式呢?下面我們來看看它的概念。

組合模式又名部分整體模式(啥又叫部分整體模式呢?上面不是說過嘛,我們可以將一棵樹理解成一個大的容器,對於該容器而言,它就是整體;然後它下面不是又有子文件或者子文件夾嘛,這些子文件或者子文件夾我們就稱之為部分,當然,部分下面是不是還可以再分出部分來啊!),是用於把一組相似的對象當作一個單一的對象。組合模式依據樹形結構來組合對象,用來表示部分以及整體層次,這種類型的設計模式屬於結構型模式,它創建瞭對象組的樹形結構。

看完以上組合模式的概念之後,相信大傢就能知道應該要使用組合模式來解決以上樹形結構所存在的問題瞭,因為對於客戶而言,他就能一致的去對待容器對象和葉子對象瞭,這樣,他使用起來也會變得更加簡單。

結構

組合模式主要包含有三種角色:

  • 抽象根節點(Component):定義系統各層次對象具有的共有方法和屬性,可以預先定義一些默認行為和屬性。

怎麼來理解抽象根節點呢?還是通過上圖來理解,不管是文件夾還是文件,我們都可以向上抽取,抽取出一個抽象類,而在這個抽象類裡面,我們就可以去定義文件和文件夾中的共有行為和屬性瞭。也就是說,正是因為客戶他想要一致的去對待容器對象和葉子對象,所以他就可以定義出這麼一個公共的抽象類瞭

  • 樹枝節點(Composite):定義樹枝節點的行為,即存儲子節點,組合樹枝節點和葉子節點形成一個樹形結構。
  • 葉子節點(Leaf):葉子節點對象,其下再無分支,是系統層次遍歷的最小單位。

組合模式案例

接下來,我們就通過一個案例再來理解一下組合模式,這個案例就是軟件菜單。

分析

先來看一下下面這張圖。

在這裡插入圖片描述

相信大傢還是比較熟悉以上這張圖的,因為我們在訪問別的一些管理系統時,經常可以看到類似的菜單。一個菜單可以包含菜單項(菜單項是指不再包含其他內容的菜單條目),也可以包含帶有其他菜單項的菜單,就拿以上系統管理菜單來說,它下面有三個子菜單,分別是菜單管理、權限配置、角色管理,它們都是屬於菜單,因為它們下面還可以有子菜單或者子菜單項。對於菜單管理來說,它下面有五個子菜單項,分別是頁面訪問、展開菜單、編輯菜單、刪除菜單、新增菜單,註意瞭,它們都是菜單項,下面不可能再有子菜單或者子菜單項瞭,故它們都是屬於葉子節點;而系統管理、菜單管理、權限配置、角色管理,它們均屬於樹枝節點,並且系統管理從根本上來說,它是屬於根節點。因此,使用組合模式來描述以上菜單就很恰當瞭。

這樣,我們的需求就是針對一個菜單,例如系統管理,打印出其包含的所有菜單以及菜單項的名稱。

需求明確之後,接下來我們就要編寫代碼解決該需求瞭。首先,對於該需求,我們先設計出一個如下的類圖。

總結

本篇文章就到這裡瞭,希望能夠給你帶來幫助,也希望您能夠多多關註WalkonNet的更多內容!

推薦閱讀: