?????? GoF 《設計模式》中說到:將對象組合成樹形結構以表示“部分 - 整體”的層次結構。 Composite 模式使得客戶對單個對象和組合對象的使用具有一致性。
?????? Composite 組合模式結構如下:
??????
說道這,我覺得有一個編程中常見的場景,就是對于樹的實現,很符合這個模式。下面我就用這個例子作一下。
?????? 首先,我們先分析對于一棵樹所包含的部分,樹干、樹枝、樹葉,其中樹干可以看成一個樹枝(就是粗了點)。那么我們就應該有兩種類實現 Leaf (樹葉)和 Limb (樹枝)。對于葉子節點和枝節點的不同在于枝節點有子樹,而葉子節點沒有子樹。為了使單個對象和組合對象的使用具有一致性,我可以將葉子節點想象成沒有子樹的枝節點。這樣我就可以得到一個抽象類,代碼如下:
??????
public
abstract
class AbstractClass
??? {
???????
public
string name;
???????
public ArrayList list;
???????
public
abstract
void Add(AbstractClass item);?????? //
增加一個子節點
???????
public
abstract
void Remove(AbstractClass item);??? //
去掉一個子節點
???????
public
abstract
string Print();???????????????????? //
打印當前節點
??? }
?????? 然后,我在對葉子節點和枝節點作不同的實現:
?????? 枝節點:
??????
public
class Limb:AbstractClass
??? {
???????
public Limb()
??????? {
??????????? list = new ArrayList();
??????? }
???????
public
override
void Add(AbstractClass item)
??????? {
??????????? list.Add(item);
??????? }
???????
public
override
void Remove(AbstractClass item)
??????? {
???????????
if(list.Contains(item))
??????????????? list.Remove(item);
??????? }
???????
public
override
string Print()
??????? {
??????????? Console.Write(name + "\n");
???????????
if(list.Count != 0)
??????????? {
???????????????
for(int i = 0;i<list.Count;i++)
??????????????? {
??????????????????? Console.Write("(Parent is " + name + ")");
??????????????????? ((AbstractClass)list[i]).Print();
??????????????? }
??????????? }
???????????
return name;
??????? }
??? }
???
葉子節點:
???
public
class Leaf:AbstractClass
??? {
???????
public Leaf()
??????? {
??????????? list = null;
??????? }
???????
public
override
void Add(AbstractClass item)
??????? {
??????? }
???????
public
override
void Remove(AbstractClass item)
??????? {
???????????
??????? }
???????
public
override
string Print()
??????? {
??????????? Console.Write(name + ",");
???????????
return
this.name;
??????? }
??? }
???
對于葉子節點來說,不需要子節點,當然也就不需要添加和刪除子節點的方法。
???
好,接下來,我們可以在客戶程序中組建一棵樹,來測試一下:
???????
static
void
??????? {
??????????? AbstractClass Tree = new Limb();
??????????? GetTree(Tree);
??????????? PrintTree(Tree);
??????????? Console.Read();
??????? }
???
???
public
static
void GetTree(AbstractClass Tree)
??????? {
??????????? Tree.name = "1";
??????????? AbstractClass leaf2 = new Leaf();
??????????? leaf2.name = "2";
??????????? Tree.Add(leaf2);
??????????? AbstractClass limb3 = new Limb();
??????????? limb3.name = "3";
??????????? Tree.Add(limb3);
??????????? AbstractClass leaf4 = new Leaf();
??????????? leaf4.name = "4";
??????????? limb3.Add(leaf4);
??????????? AbstractClass leaf5 = new Leaf();
??????????? leaf5.name = "5";
??????????? limb3.Add(leaf5);
??????? }
???????
public
static
void PrintTree(AbstractClass Tree)
??????? {
??????????? Tree.Print();
??????? }
???
輸出結果如下:
1
(Parent is 1)2,(Parent is 1)3
(Parent is 3)4,(Parent is 3)5,
在組織這個樹時,的確能感覺到
GoF
《設計模式》中的那句話:
單個對象和組合對象的使用具有一致性。當然也的確感覺到一點矛盾:對于葉子節點來說,不需要
ArrayList
和
Add
()
Remove
()應該不繼承才對,當然如果在代碼執行性能可以達到要求的情況下,簡化一下編碼實現復雜度也是挺好的一件事。
最后在來說說 Composite 組合模式的幾個要點:
?????? 1 、 Composite 模式采用樹形結構來實現普遍存在的對象容器,從而將“一對多”的關系轉化為“一對一”的關系,使得客戶代碼可以一致的處理對象和對象容器,無需關心處理的是單個對象,還是組合的對象容器。
2 、將“客戶代碼與復雜的對象容器結構”解耦是 Composite 模式的核心思想,解耦之后,客戶代碼將與純粹的對象接口——而非對象容器的復雜內部實現結構——發生依賴關系,從而更能“應對變化”。
3 、 Composite 模式中,是將“ Add 和 Remove 的和對象容器相關的方法”定義在“表示抽象對象的 Component 類”中,還是將其定義在“表示對象容器的 Composite 類”中,是一個關乎“透明性”和“安全性”的兩難問題,需要仔細權衡結構,這又是必須付出的代價。
4 、 Composite 模式在具體實現中,可以讓父對象中的字對象反向追溯:如果父對象有頻繁的遍歷需求,可使用緩存技巧來改善效率