大話設計模式:第19章 組合模式

第19章:組合模式

組合模式

組合模式(Composite):將對象組合成樹形結構以表示“部分-整體”的層次結構。組合模式使得用戶對單個對象和組合對象的使用具有一致性。

在這裏插入圖片描述

組合模式適合處理整體與部分可以被一致對待的問題。

Component爲組合中的對象聲明接口,在適當情況下,實現所有類共有接口的默認行爲。聲明一個接口用於訪問和管理Component的子部件。

在這裏插入圖片描述

Leaf在組合中表示葉節點對象,葉節點沒有子節點。

在這裏插入圖片描述

Composite定義有枝節點行爲,用來存儲子部件,在Component接口中實現與子部件有關的操作,比如增加Add和刪除Remove

在這裏插入圖片描述

客戶端代碼,能通過Component接口操作組合部件的對象。

在這裏插入圖片描述

結果顯示

在這裏插入圖片描述

透明方式與安全方式

透明方式Leaf類不可以再長分枝,但Leaf類也有AddRemove方法,即在Component類中聲明所有用來管理子對象的方法,這樣實現Component接口的所有子類都具備了AddRemove等方法。這樣做的好處是葉節點枝節點對於外界沒有區別,它們具備完全一致的行爲接口。但問題是,Leaf類本身不具備AddRemove方法的功能,所以實現它沒有意義。

安全方式:在Component接口中不聲明AddRemove方法,則子類Leaf無需實現AddRemove方法,在子類Composite中聲明所有用來管理子類對象的方法。不過由於不夠透明,所以樹葉和樹枝類將不具有相同的接口,客戶端的調用需要做相應的判斷。

組合模式的使用

當需求是體現部分與整體層次的結構時,並且用戶希望忽略組合對象與單個對象的不同、統一地使用組合結構中的所有對象,應該使用組合模式。

例:ASP.NETTreeView控件、自定義控件(把一些基本的控件組合起來,通過編程寫成個定製的控件,比如用兩個文本框和一個按鈕可以定義的登錄框控件)。

所有的Web控件的基類都是System.Web.UI.Control,而Control基類中就有AddRemove方法,這就是典型的組合模式的應用。

組合模式的好處

  1. 組合模式定義了包含基本對象和組合對象的類層次結構。基本對象可以被組合成更復雜的組合對象,而這個組合對象又可以被組合,這樣不斷地遞歸下去,客戶代碼中,任何用到基本對象的地方都可以使用組合對象。

  2. 用戶不用關心到底是處理一個葉節點還是處理一個組合組件,也就不用爲定義組合而寫一些選擇判斷語句,即,組合模式讓客戶可以一致地使用組合結構和單個對象。

組合模式示例

任務:公司管理系統

在這裏插入圖片描述

from abc import ABC, abstractmethod
from typing import Text
class Company(ABC):
    """
    公司類(抽象類或接口)
    """
    def __init__(self, name: Text):
        self._name = name
    
    @abstractmethod
    def add(self, c: object) -> None:
        """
        增加
        """
        pass
    @abstractmethod
    def remove(self, c: object) -> None:
        """
        移除
        """
        pass
    @abstractmethod
    def display(self, depth: int) -> None:
        """
        顯示
        """
        pass
    @abstractmethod
    def line_of_duty(self) -> None:
        """
        履行職責
        """
        pass
    
class ConcreteCompany(Company):
    """
    具體公司類(實現接口樹枝節點)
    """
    
    def __init__(self, name: Text):
        super(ConcreteCompany, self).__init__(name)
        self.__children = []
        
    def add(self, c: Company) -> None:
        self.__children.append(c)
        
    def remove(self, c: Company) -> None:
        self.__children.remove(c)
        
    def display(self, depth: int) -> None:
        print("-" * depth, self._name)
        for component in self.__children:
            component.display(depth + 2)
            
    def line_of_duty(self) -> None:
        for component in self.__children:
            component.line_of_duty()
            
class HRDepartment(Company):
    """
    人力資源部與財務部類樹葉節點
    """
    
    def __init__(self, name: Text):
        super(HRDepartment, self).__init__(name)
        
    def add(self, c: Company) -> None:
        pass
        
    def remove(self, c: Company) -> None:
        pass
        
    def display(self, depth: int) -> None:
        print("-" * depth, self._name)
        
    def line_of_duty(self) -> None:
        print(self._name, "員工招聘培訓管理")
        
class FinanceDepartment(Company):
    """
    人力資源部與財務部類樹葉節點
    """
    
    def __init__(self, name: Text):
        super(FinanceDepartment, self).__init__(name)
        
    def add(self, c: Company) -> None:
        pass
        
    def remove(self, c: Company) -> None:
        pass
        
    def display(self, depth: int) -> None:
        print("-" * depth, self._name)
        
    def line_of_duty(self) -> None:
        print(self._name, "公司財務收支管理")
        
# 客戶端調用

if __name__ == "__main__":
    
    root = ConcreteCompany("北京總公司")
    root.add(HRDepartment("總公司人力資源部"))
    root.add(FinanceDepartment("總公司財務部"))
    
    comp = ConcreteCompany("上海華東分公司")
    comp.add(HRDepartment("華東分公司人力資源部"))
    comp.add(FinanceDepartment("華東分公司財務部"))
    root.add(comp)
    
    comp1 = ConcreteCompany("南京辦事處")
    comp1.add(HRDepartment("南京辦事處人力資源部"))
    comp1.add(FinanceDepartment("南京辦事處財務部"))
    comp.add(comp1)
    
    comp2 = ConcreteCompany("杭州辦事處")
    comp2.add(HRDepartment("杭州辦事處人力資源部"))
    comp2.add(FinanceDepartment("杭州辦事處財務部"))
    comp.add(comp2)
    
    print("**結構圖**")
    root.display(1)
    
    print("**職責**")
    root.line_of_duty()
**結構圖**
- 北京總公司
--- 總公司人力資源部
--- 總公司財務部
--- 上海華東分公司
----- 華東分公司人力資源部
----- 華東分公司財務部
----- 南京辦事處
------- 南京辦事處人力資源部
------- 南京辦事處財務部
----- 杭州辦事處
------- 杭州辦事處人力資源部
------- 杭州辦事處財務部
**職責**
總公司人力資源部 員工招聘培訓管理
總公司財務部 公司財務收支管理
華東分公司人力資源部 員工招聘培訓管理
華東分公司財務部 公司財務收支管理
南京辦事處人力資源部 員工招聘培訓管理
南京辦事處財務部 公司財務收支管理
杭州辦事處人力資源部 員工招聘培訓管理
杭州辦事處財務部 公司財務收支管理
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章