Composite(組合模式)
Composite(組合模式)屬於結構型模式,是一種統一管理樹形結構的抽象方式。
意圖:將物件組合成樹形結構以表示 “部分 - 整體” 的層次結構。Composite 使得使用者對單個物件和組合物件的使用具有一致性。
舉例子
如果看不懂上面的意圖介紹,沒有關係,設計模式需要在日常工作裡用起來,結合例子可以加深你的理解,下面我準備了三個例子,讓你體會什麼場景下會用到這種設計模式。
公司組織關係樹
公司組織關係可能分為部門與人,其中人屬於部門,有的人有下屬,有的人沒有下屬。如果我們統一將部門、人抽象為組織節點,就可以方便的統計某個部門下有多少人、財務資料等等,而不用關心當前節點是部門還是人。
作業系統的資料夾與檔案
作業系統的資料夾與檔案也是典型的樹狀結構,為了方便遞迴出文件夾內檔案數量或者檔案總大小,我們最好設計的時候就將資料夾與檔案抽象為檔案,這樣每個節點都擁有相同的方法新增、刪除、查詢子元素,而不需要關心當前節點是資料夾或是檔案。
搭建平臺的元件與容器
容器與元件的關係很小,使用者常常認為容器也是一種元件,但搭建平臺實現時,容器與元件稍有不同,不同之處在於容器可以巢狀子元素,而元件不可以。如果因此搭建平臺就將元件分為容器與元件,會導致 API 割裂為兩套,不利於元件開發者維護與使用者理解,比較好的設計思路是將元件與容器統一看成元件,元件只是一種沒有子元素的特殊容器,這樣元件與容器就可以擁有相同的 API,統一理解與操作了。
意圖解釋
意圖:將物件組合成樹形結構以表示 “部分 - 整體” 的層次結構。Composite 使得使用者對單個物件和組合物件的使用具有一致性。
比較好理解,組合是指多個物件雖然有一定差異,但共同組合成了一個樹形結構,那麼物件之間就一定存在 “部分 - 整體” 的關係,組合模式要求我們抽象一個物件
Component
作為統一操作模型,葉子結點與非葉子結點都實現了所有功能,即便是沒有子元素的葉子結點,為了強調透明性,還是具備比如
getChildren
方法,只不過永遠都返回
null
。
結構圖
其中
Component
是組合中物件宣告介面,一般會實現所有公共類的所有介面,還要提供一個介面管理其子元件。
Leaf
表示葉子結點,沒有子結點,相應的
Composite
就是有子結點的節點。
可以看到,組合模式就是將樹狀結構中所有節點統一抽象了,
我們不需要關心葉子結點與非葉子結點的差異,而可以透過組合模式的抽象遮蔽掉這些差異,統一處理。
程式碼例子
下面例子使用 typescript 編寫。
// 統一的抽象
class Component {
// 新增子元素
public add() {}
// 獲取名稱
public getName() {}
// 獲取子元素
public getChildren() {}
}
// 非葉子結點
class Composite extends Component {
public add(component: Component) {
this。children。push(component)
}
public getName() {
return this。name
}
public getChildren() {
return this。children
}
}
// 葉子結點
class Leaf extends Component {
public add(component: Component) {
throw Error(‘葉子結點無法新增元素’)
}
public getName() {
return this。name
}
public getChildren() {
return null
}
}
最後我們把對所有節點的操作都轉為
Component
物件,而不用關心這個物件具體是
Composite
或
Leaf
。
弊端
組合模式進行了一層抽象,其實增加了複雜系統中業務複雜度。如果
Composite
與
Leaf
差異過大,那麼統一抽象帶來的理解成本是很高的。
同時,
Leaf
不得不實現一些僅
Composite
存在的空函式,比如
add
delete
,即便這些方法對他們是無意義的,此時可能要進行統一的無效或錯誤處理,才能使業務層真正不用感知他們的區別,否則
add
可能會失敗,其本質上還是將節點的區別暴露給了業務層。
總結
組合模式是針對樹狀結構這個特定場景的統一抽象方案,對降低系統複雜度有很重要的意義,同時也不要忘了過度抽象是有害的,我們要拿捏其中的度。
下圖做了一個簡單的解釋:
程式中始終關注
Component
就行了,樹狀結構的差異已經被抹平。
討論地址是:
精讀《設計模式 - Composite 組合模式》· Issue #284 · dt-fe/weekly
如果你想參與討論,請 點選這裡,每週都有新的主題,週末或週一釋出。前端精讀 - 幫你篩選靠譜的內容。
關注
前端精讀微信公眾號
版權宣告:自由轉載-非商用-非衍生-保持署名(
創意共享 3.0 許可證
)