github地址:https://github.com/cheesezh/python_design_patternspython
組合模式,將對象組合成樹形結構以表示「部分-總體」的層次結構。組合模式使得用戶對單個對象和對組合對象的使用具備一致性[DP]。git
from abc import ABCMeta, abstractmethod class Component(): """ Component爲組合中的對象聲明接口,在適當狀況下,實現全部類共有接口的默認行爲。 聲明一個接口用於訪問和管理Component的子部件。 """ __metaclass__ = ABCMeta def __init__(self, name): self.name = name @abstractmethod def add(self, c): """ 一般用add來增長樹枝或樹葉 """ pass @abstractmethod def remove(self, c): """ 一般用remove來刪除樹枝或樹葉 """ pass @abstractmethod def display(self, depth): pass class Leaf(Component): """ 葉子節點 """ def add(self, c): print("葉子節點沒法添加子節點") def remove(self, c): print("葉子節點沒法刪除子節點") def display(self, depth): print("-"*depth, self.name) class Composite(Component): """ 子部件節點 """ def __init__(self, name): super().__init__(name) self.children = [] def add(self, c): self.children.append(c) def remove(self, c): self.children.remove(c) def display(self, depth): print("-"*depth, self.name) for c in self.children: c.display(depth+2) def main(): root = Composite("root") root.add(Leaf("Leaf A")) root.add(Leaf("Leaf B")) comp = Composite("Composite X") comp.add(Leaf("Leaf XA")) comp.add(Leaf("Leaf XB")) root.add(comp) comp2 = Composite("Composite XY") comp2.add(Leaf("Leaf XYA")) comp2.add(Leaf("Leaf XYB")) comp.add(comp2) root.add(Leaf("Leaf C")) leaf_d = Leaf("Leaf D") root.add(leaf_d) root.remove(leaf_d) root.display(1) main()
- root --- Leaf A --- Leaf B --- Composite X ----- Leaf XA ----- Leaf XB ----- Composite XY ------- Leaf XYA ------- Leaf XYB --- Leaf C
Leaf類中也有Add和Reomve,可是樹葉不能夠再長分枝。這種方式叫作透明方式,也就是說再Component中聲明全部用來管理子對象的方法,其中包括add,remove等。這樣Component抽象類的全部子類都具有了add和remove。這樣的好處在於葉子節點和分枝節點對於外界沒有區別,它們具有徹底一致的行爲接口。可是問題也比較明顯,由於Leaf類自己不具有add和remove等功能,因此實現它是沒有意義的。github
另外一種是安全方式,也就是在Component接口中不去聲明add和remove方法,那麼子類Leaf也就不須要去實現它,而是在Composite聲明全部用來管理子類對象的方法,這樣作就不會出現剛纔提到的問題,不過因爲不透明,因此樹葉和樹枝類將有不一樣的接口,客戶端調用須要作相應的判斷,帶來了不便。安全
當需求中是體現部分與總體層次的結構時,以及但願用戶能夠忽略組合對象與單個對象的不一樣,統一地使用組合結構中的全部對象時,就應該考慮用組合模式了。架構
使用組合模式,模擬公司管理系統。app
from abc import ABCMeta, abstractmethod class Company(): """ 抽象公司類 """ __metaclass__ = ABCMeta def __init__(self, name): self.name = name @abstractmethod def add(self, c): """ 一般用add來增長樹枝或樹葉 """ pass @abstractmethod def remove(self, c): """ 一般用remove來刪除樹枝或樹葉 """ pass @abstractmethod def display(self, depth): pass @abstractmethod def line_of_duty(self): pass class ConcreteCompany(Company): """ 具體公司類 """ def __init__(self, name): super().__init__(name) self.children = [] def add(self, c): self.children.append(c) def remove(self, c): self.children.remove(c) def display(self, depth): print("-"*depth, self.name) for c in self.children: c.display(depth+2) def line_of_duty(self): for c in self.children: c.line_of_duty() class HRDepartment(Company): """ 人力資源部 """ def add(self, c): pass def remove(self, c): pass def display(self, depth): print("-"*depth, self.name) def line_of_duty(self): print("{}負責員工招聘。".format(self.name)) class FinanceDepartment(Company): """ 財務部 """ def add(self, c): pass def remove(self, c): pass def display(self, depth): print("-"*depth, self.name) def line_of_duty(self): print("{}負責財務收支。".format(self.name)) def 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() main()
組織架構圖 - 北京總公司 --- 總公司人力資源部 --- 總公司財務部 --- 上海華東分公司 ----- 華東分公司人力資源部 ----- 華東分公司財務部 ----- 南京辦事處 ------- 南京辦事處人力資源部 ------- 南京辦事處財務部 ----- 杭州辦事處 ------- 杭州辦事處人力資源部 ------- 杭州辦事處財務部 履行職責 總公司人力資源部負責員工招聘。 總公司財務部負責財務收支。 華東分公司人力資源部負責員工招聘。 華東分公司財務部負責財務收支。 南京辦事處人力資源部負責員工招聘。 南京辦事處財務部負責財務收支。 杭州辦事處人力資源部負責員工招聘。 杭州辦事處財務部負責財務收支。
組合模式定義了包含人力資源部和財務部這些基本對象和分公司,辦事處等組合對象的類層次結構。基本對象能夠被組合成共複雜的組合對象,而這個組合對象又能夠被組合,這樣不斷地遞歸下去,客戶端代碼中,任何用到基本對象的地方均可以使用組合對象了。用戶不用關心究竟是處理一個葉子節點仍是處理一個組合組件,也用不着爲定義組合而寫一些選擇判斷語句。code
簡單的說,組合模式讓客戶能夠一致地使用組合結構和單個對象。orm