3) 樹枝構件角色Composite:在組合中表示分支節點對象——有子節點,實現抽象構件角色聲明的接口;存儲子部件。
Component:
為組合中的對象聲明接口;
在適當的情況下,實現所有類共有接口的缺省行為;
聲明一個接口用於訪問和管理Component的子組件。
Leaf:
在組合中表示葉節點對象,葉節點沒有子節點;
在組合中定義葉節點的行為。
Composite:
定義有子部件的那些部件的行為;
存儲子部件。
Client:
通過Component接口操作組合部件的對象。
組合模式中必須提供對子對象的管理方法,不然無法完成對子對象的添加刪除等等操作,也就失去了靈活性和擴展性。但是管理方法是在Component中就聲明還是在Composite中聲明呢?
一種方式是在Component裡面聲明所有的用來管理子類對象的方法,以達到Component接口的最大化(如下圖所示)。目的就是為了使客戶看來在接口層次上樹葉和分支沒有區別——透明性。但樹葉是不存在子類的,因此Component聲明的一些方法對於樹葉來說是不適用的。這樣也就帶來了一些安全性問題。
另一種方式就是只在Composite裡面聲明所有的用來管理子類對象的方法(如下圖所示)。這樣就避免了上一種方式的安全性問題,但是由於葉子和分支有不同的接口,所以又失去了透明性。
《設計模式》一書認為:在這一模式中,相對於安全性,我們比較強調透明性。對於第一種方式中葉子節點內不需要的方法可以使用空處理或者異常報告的方式來解決。
#include#include #include using namespace std; // 抽象的部件類描述將來所有部件共有的行為 class Component { public: Component(string name) : m_strCompname(name){} virtual ~Component(){} virtual void Operation() = 0; virtual void Add(Component *) = 0; virtual void Remove(Component *) = 0; virtual Component *GetChild(int) = 0; virtual string GetName() { return m_strCompname; } virtual void Print() = 0; protected: string m_strCompname; }; class Leaf : public Component { public: Leaf(string name) : Component(name) {} void Operation() { cout<::iterator it = m_vecComp.begin(); while (it != m_vecComp.end()) { if (*it != NULL) { cout<<----delete <<(*it)->GetName()<<----< ::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it) { if ((*it)->GetName() == pComponent->GetName()) { if (*it != NULL) { delete *it; *it = NULL; } m_vecComp.erase(it); break; } } } Component *GetChild(int index) { if (index > m_vecComp.size()) { return NULL; } return m_vecComp[index - 1]; } void Print() { for (vector ::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it) { cout<<(*it)->GetName()< m_vecComp; }; int main(int argc, char *argv[]) { Component *pNode = new Composite(Beijing Head Office); Component *pNodeHr = new Leaf(Beijing Human Resources Department); Component *pSubNodeSh = new Composite(Shanghai Branch); Component *pSubNodeCd = new Composite(Chengdu Branch); Component *pSubNodeBt = new Composite(Baotou Branch); pNode->Add(pNodeHr); pNode->Add(pSubNodeSh); pNode->Add(pSubNodeCd); pNode->Add(pSubNodeBt); pNode->Print(); Component *pSubNodeShHr = new Leaf(Shanghai Human Resources Department); Component *pSubNodeShCg = new Leaf(Shanghai Purchasing Department); Component *pSubNodeShXs = new Leaf(Shanghai Sales department); Component *pSubNodeShZb = new Leaf(Shanghai Quality supervision Department); pSubNodeSh->Add(pSubNodeShHr); pSubNodeSh->Add(pSubNodeShCg); pSubNodeSh->Add(pSubNodeShXs); pSubNodeSh->Add(pSubNodeShZb); pNode->Print(); // 公司不景氣,需要關閉上海質量監督部門 pSubNodeSh->Remove(pSubNodeShZb); if (pNode != NULL) { delete pNode; pNode = NULL; } return 0; }
Component是否應該實現一個Component列表,在上面的代碼中,我是在Composite中維護的列表,由於在Leaf中,不可能存在子Composite,所以在Composite中維護了一個Component列表,這樣就減少了內存的浪費;
內存的釋放;由於存在樹形結構,當父節點都被銷毀時,所有的子節點也必須被銷毀,所以,我是在析構函數中對維護的Component列表進行統一銷毀,這樣就可以免去客戶端頻繁銷毀子節點的困擾;
由於在Component接口提供了最大化的接口定義,導致一些操作對於Leaf節點來說並不適用,比如:Leaf節點並不能進行Add和Remove操作,由於Composite模式屏蔽了部分與整體的區別,為了防止客戶對Leaf進行非法的Add和Remove操作,所以,在實際開發過程中,進行Add和Remove操作時,需要進行對應的判斷,判斷當前節點是否為Composite。