Design Patterns - Component

大學要有夢想發表於2020-12-29

Composite(組合) — 物件結構型模式

當有將物件組合成樹形結構來表示“部分 - 整體” 的層次結構時,我們可以使用 Composite 模式,Composite 使得使用者對單個物件和組合物件的使用具有一致性。

適用場景

  1. 你想表示物件的部分 - 整體層次結構。
  2. 你想使用者忽略組合物件與單個物件的不同,使用者將統一地使用組合結構中的物件。

UML 圖

在這裡插入圖片描述

效果

  1. 定義了包含基本物件和組合物件的類層次機構:基本物件可以被組合成更復雜的組合物件,而這個組合物件又可以被組合,這樣不斷地遞迴下去。客戶程式碼中,任何用到基本物件的地方都可以使用組合物件。
  2. 簡化客戶程式碼:客戶可以一致的使用組合結構和單個物件。通常使用者不知道(也不關心)處理的是一個葉結點還是一個組合元件。這就簡化了客戶程式碼,因為在定義組合的那些類中不需要寫一些充斥著選擇語句的函式。
  3. 使得更容易增加新型別的元件:新定義的 Composite 或 Leaf 子類自動地與已有的結構的客戶程式碼一起工作,客戶程式不需要因新的 Component 類而改變。
  4. 使你的設計變得更加一般化:容易增加新元件也會產生一些問題,那就是很難限制組合中的元件。有時你希望一個組合只能有某些特定的元件。使用 Composite 時,你不能依賴型別系統施加這些約束,而必須在執行時進行檢查。

幾個問題

  1. 最大化 Component 介面:
    Composite 模式的目的之一是使得使用者不知道他們正在使用具體的 Leaf 類和 Composite 類。為了達到這一目的,Composite 類應為 Leaf 和 Composite 類儘可能多定義一些公共操作。Composite 類通常為這些操作提供預設的實現,而 Leaf 和Composite 子類可以對它們進行重定義。
    然而,這個目標有時可能會與類層次結構設計原則相沖突,該原則規定:一個類只能定義那些對它的子類有意義的操作。有許多 Component 所支援的操作對 Leaf 類似乎沒有什麼意義,那麼 Component 怎樣為它們提供一個預設的操作呢?
    即把 Leaf 看成一個沒有子節點的 Component,就可以在 Component 類中定義一個預設的操作。

  2. 宣告管理子部件的操作:
    雖然 Composite 類實現了 Add 和 Remove 操作用於管理子部件,但在 Composite 模式中一個重要的問題是:在 Composite 類層次結構中那些類宣告這些操作。我們是應該在 Component 中宣告這些操作,並使這些操作對 Leaf 類有意義,還是隻應該在 Composite 和它的子類中宣告並定義這些操作呢?
    這需要在安全性和透明性之間做出選擇。

    • 在類層次結構的根部定義子節點管理介面的方法具有良好的透明性,因為你可以一致的使用所有的元件,但是這一方法是以安全性為代價的,因為客戶有可能會做一些無意義的事情,例如在 Leaf 中增加和刪除物件等。
    • 在 Composite 類中定義管理子部件的方法具有良好的安全性,因為在像 C++ 這樣的靜態型別語言中,在編譯時任何從 Leaf 中增加或刪除物件的嘗試都會被發現。但這又損失了透明性,因為 Leaf 和 Composite 具有不同的介面。

    在這一模式中,相對於安全性,我們比較強調透明性。如果你選擇了安全性,有時你可能會丟失型別資訊,並且不得不將一個元件轉換成一個組合。這樣的型別轉換必定不是安全的。

示例

# coding=utf-8
class Component:
    def __init__(self, name):
        self.name = name

    def add(self, comp):
        pass

    def remove(self, comp):
        pass

    def display(self, depth):
        pass

class Leaf(Component):
    def display(self, depth):
        strtemp = ''
        for i in range(depth):
            strtemp += '---'
        print(strtemp + self.name)

class Composite(Component):
    def __init__(self, name):
        super(Composite, self).__init__(name)
        self.children = []

    def add(self, comp):
        self.children.append(comp)

    def remove(self, comp):
        self.children.remove(comp)

    def display(self, depth):
        strtemp = ''
        for i in range(depth):
            strtemp += '---'
        print(strtemp + self.name)
        for comp in self.children:
            comp.display(depth + 2)

client

if __name__ == "__main__":
    root = Composite('根')

    root.add(Leaf('葉1a'))
    root.add(Leaf('葉1b'))
    root.add(Leaf('花1a'))
    root.add(Leaf('花1b'))
    comp1a = Composite('枝1a')
    comp1b = Composite('枝1b')
    root.add(comp1a)
    root.add(comp1b)

    comp1a.add(Leaf('葉2a'))
    comp1a.add(Leaf('葉2b'))
    comp1a.add(Leaf('花2a'))
    comp1a.add(Leaf('花2b'))
    comp2a = Composite('枝2a')
    comp1a.add(comp2a)

    comp1b.add(Leaf('葉2a'))
    comp1b.add(Leaf('花2a'))

    comp2a.add(Leaf('葉3a'))
    comp2a.add(Leaf('花3a'))
    comp3a = Composite('枝3a')
    comp2a.add(comp3a)

    comp3a.add(Leaf('葉4a'))
    comp3a.add(Leaf('花4a'))
    root.display(1)
"""
output:
---根
---------葉1a
---------葉1b
---------花1a
---------花1b
---------枝1a
---------------葉2a
---------------葉2b
---------------花2a
---------------花2b
---------------枝2a
---------------------葉3a
---------------------花3a
---------------------枝3a
---------------------------葉4a
---------------------------花4a
---------枝1b
---------------葉2a
---------------花2a

Process finished with exit code 0

"""

相關文章