問題
在開發中,我們經常可能要遞迴構建樹狀的組合結構。
當你發現需求中是體現部分與整體層次的結構時,以及你希望使用者可以忽略組合對象與當個對象的不同,統一的使用組合結構中的所有對象時,應該考慮用組合模式。
composite組合模式
將對象組合成樹形結構以表示“部分-整體”的階層。它使得客戶對單個對象和組合對象的使用具有一致性。
component組件:為組合中的對象聲明介面,聲明了類共有介面的預設行為。聲明一個介面函數用於訪問和管理Component的子組件
composite組合:定義有枝節點行為,用來儲存子組件,在component介面中實現與子組件有關的操作,Add,Remove等
leaf葉子:在組合模式中表示分葉節點對象,分葉節點沒有子節點
Component模式是為解決組件之間的遞迴組合提供瞭解決的辦法,它主要分為兩個衍生類別,其中的Leaf是葉子結點,也就是不含有子組件的結點,而Composite是含有子組件的類.舉一個例子來說明這個模式,在UI的設計中,最基本的控制項是諸如Button,Edit這樣的控制項,相當於是這裡的Leaf組件,而比較複雜的控制項比如List則可也看做是由這些基本的組件組合起來的控制項,相當於這裡的Composite,它們之間有一些行為含義是相同的,比如在控制項上作一個點擊,移動操作等等的,這些都可以定義為抽象基類中的介面虛函數,由各個衍生類別去實現之,這些都會有的行為就是這裡的Operation函數,而添加,刪除等進行組件組合的操作只有非葉子結點才可能有,所以虛擬基類中只是提供介面而且預設的實現是什麼都不做.
composite組合模式比較容易理解,想到composite組合模式就應該想到樹形結構圖。組合體內這些對象都有共同介面,當組合體一個對象的方法被調用執行時,composite將遍曆(iterator)整個樹形結構,尋找同樣包含這個方法的對象並調用執行。可以用牽一動百來形容。所以composite組合模式使用到了Iterator模式,和Chain Of Responsibility模式類似。
小demo
composite.h
/********************************************************************created:2006/07/20filename: Composite.hauthor:李創http://www.cppblog.com/converse/purpose:Composite模式的示範代碼*********************************************************************/#ifndef COMPOSITE_H#define COMPOSITE_H#include <string>#include <list>using namespace std;// 組合中的抽象基類class Component{private: string m_strName;public:Component(string paramName){m_strName=paramName;}virtual ~Component(){} // 純虛函數,只提供介面,沒有預設的實現virtual void Operation() = 0;// 虛函數,提供介面,有預設的實現就是什麼都不做 virtual void Add(Component* pChild){}//添加一個子組件 virtual void Remove(Component* pChild){}//刪除一個子組件 virtual Component* GetChild(int nIndex){return NULL;}//擷取子組件的指標};// 派生自Component,是其中的葉子組件的基類class Leaf : public Component{public: Leaf(string strParam):Component(strParam){}virtual ~Leaf(){}virtual void Operation();};// 派生自Component,是其中的含有子件的組件的基類class Composite: public Component{public: Composite(string strParam):Component(strParam){}virtual ~Composite();virtual void Operation();virtual void Add(Component* pChild);virtual void Remove(Component* pChild);virtual Component* GetChild(int nIndex);private:// 採用list容器去儲存子組件std::list<Component*>m_ListOfComponent;};#endif
composite.cpp
/********************************************************************created:2006/07/20filename: Composite.cppauthor:李創http://www.cppblog.com/converse/purpose:Composite模式的示範代碼*********************************************************************/#include "Composite.h"#include <iostream>#include <algorithm> /*-------------------------------------------------------------------Leaf成員函數的實現-------------------------------------------------------------------*/void Leaf::Operation(){ static int a=0; a=a++;std::cout << "Operation by leaf\n"<<a<<endl;}/*-------------------------------------------------------------------Composite成員函數的實現-------------------------------------------------------------------*/Composite::~Composite(){std::list<Component*>::iterator iter1, iter2, temp;for (iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end(); iter1 != iter2; ){temp = iter1;++iter1;delete (*temp);}}void Composite::Add(Component* pChild){m_ListOfComponent.push_back(pChild);}void Composite::Remove(Component* pChild){std::list<Component*>::iterator iter;iter = find(m_ListOfComponent.begin(), m_ListOfComponent.end(), pChild);if (m_ListOfComponent.end() != iter){m_ListOfComponent.erase(iter);}}Component* Composite::GetChild(int nIndex){if (nIndex <= 0 || nIndex > m_ListOfComponent.size())return NULL;std::list<Component*>::iterator iter1, iter2;int i;for (i = 1, iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();iter1 != iter2;++iter1, ++i){if (i == nIndex)break;}return *iter1;}void Composite::Operation(){std::cout << "Operation by Composite\n";std::list<Component*>::iterator iter1, iter2;for (iter1 = m_ListOfComponent.begin(), iter2 = m_ListOfComponent.end();iter1 != iter2;++iter1){(*iter1)->Operation();}}
main.cpp
#include "Composite.h"#include <stdlib.h> int main(){ Composite* pComposite = new Composite("Compostie");pComposite->Add(new Leaf("leaf1"));pComposite->Add(new Leaf("leaf2"));pComposite->Operation();pComposite->GetChild(2)->Operation(); delete pComposite; Composite* myComposite = new Composite("myCompostie"); myComposite->Add(new Leaf("leaf3")); delete myComposite;system("pause");return 0;}
好處:
1.使用戶端調用簡單,用戶端可以一致的使用組合結構或單個對象,使用者就不必關心自己處理的是單個對象還是整個組合結構,這就簡化了用戶端代碼
2.更容易在組合體內加入對象組件。用戶端不必因為加入了新的對象組件二更改代碼。
如何使用composite?
首先定義一個介面或抽象類別,這是設計模式的通用方式,其他設計模式對介面內部定義限制不多,composite卻有個規定,那就是要在介面內部定義一個用於訪問和管理composite組合體對象們(或稱組件component)。