Composite組合模式
做用:將對象組合成樹形結構以表示「部分-總體」的層次結構。Composite使得用戶對單個對象和組合對象的使用具備一致性。ios
UML圖以下:函數
在Component中聲明全部用來管理子對象的方法,其中包括Add、Remove等,這樣實現Component接口的全部子類都具有了Add和Remove。
這樣作的好處就是葉節點和枝節點對於外界沒有區別,它們具有 徹底一致的行爲 接口。
但問題也很明顯,由於Leaf類自己不具有Add()、Remove()方法的 功能,因此實現它是沒有意義的。
什麼時候使用組合模式:
當你發現需求中是體現部分與總體層次的結構時,以及你但願用戶能夠忽略組合對象與單個對象的不一樣,統一地使用組合結構中的全部對象時,就應該考慮用組合模式了。
基本對象能夠被組合成更復雜的組合對象,而這個組合對象又能夠被組合,這樣不斷地遞歸下去,客戶代碼中,任何用到基本對象的地方均可以使用組合對象了。
用戶不用關心究竟是處理一個葉節點仍是處理一個組合組件,也就用不着爲定義組合二寫一些選擇判斷語句了。
組合模式讓客戶能夠一致地使用組合結構和單個對象。
抽象基類:
1)Component:爲組合中的對象聲明接口,聲明瞭類共有接口的缺省行爲(如這裏的Add,Remove,GetChild函數),聲明一個接口函數能夠訪問Component的子組件.
接口函數:
1)Component::Operatation:定義了各個組件共有的行爲接口,由各個組件的具體實現.
2)Component::Add添加一個子組件
3)Component::Remove::刪除一個子組件.
4)Component::GetChild:得到子組件的指針.
說明:
Component模式是爲解決組件之間的遞歸組合提供瞭解決的辦法,它主要分爲兩個派生類:post
1)、Leaf是葉子結點,也就是不含有子組件的結點this
2)、Composite是含有子組件的類.spa
舉一個例子來講明這個模式,在UI的設計中,最基本的控件是諸如Button、Edit這樣的控件,至關因而這裏的Leaf組件,而比較複雜的控件好比Panel則可也看作是由這些基本的組件組合起來的控件,至關於這裏的Composite,它們之間有一些行爲含義是相同的,好比在控件上做一個點擊,移動操做等等的,這些均可以定義爲抽象基類中的接口虛函數,由各個派生類去實現之,這些都會有的行爲就是這裏的Operation函數,而添加、刪除等進行組件組合的操做只有非葉子結點纔可能有,因此虛擬基類中只是提供接口並且默認的實現是什麼都不作。.net
代碼以下:設計
Composite.h指針
1 #ifndef _COMPOSITE_H_ 2 #define _COMPOSITE_H_ 3 4 #include <vector> 5 6 using namespace std; 7 8 /* 9 Component抽象基類,爲組合中的對象聲明接口,聲明瞭類共有接口的缺省行爲(如這裏的Add,Remove,GetChild函數), 10 聲明一個接口函數能夠訪問Component的子組件. 11 */ 12 class Component 13 { 14 public: 15 //純虛函數,只提供接口,沒有默認的實現 16 virtual void Operation()=0; 17 18 // 虛函數,提供接口,有默認的實現就是什麼都不作 19 virtual void Add(Component*); 20 virtual void Remove(Component*); 21 virtual Component* GetChild(int index); 22 virtual ~Component(); 23 protected: 24 Component(); 25 }; 26 27 //Leaf是葉子結點,也就是不含有子組件的結點類,因此不用實現Add、Remove、GetChild等方法 28 class Leaf:public Component 29 { 30 public: 31 //只實現Operation接口 32 virtual void Operation(); 33 Leaf(); 34 ~Leaf(); 35 }; 36 37 //Composite:含有子組件的類 38 class Composite:public Component 39 { 40 public: 41 Composite(); 42 ~Composite(); 43 //實現全部接口 44 void Operation(); 45 void Add(Component*); 46 void Remove(Component*); 47 Component* GetChild(int index); 48 private: 49 //這裏採用vector來保存子組件 50 vector<Component*> m_ComVec; 51 }; 52 #endif
Compostie.cppcode
1 #include "Composite.h" 2 #include <iostream> 3 4 using namespace std; 5 6 Component::Component() 7 {} 8 9 Component::~Component() 10 {} 11 12 void Component::Add(Component* com) 13 { 14 cout << "add" << endl; 15 } 16 17 void Component::Remove(Component* com) 18 { 19 } 20 21 void Component::Operation() 22 { 23 cout << "Component::Operation" << endl; 24 } 25 26 Component* Component::GetChild(int index) 27 { 28 return NULL; 29 } 30 31 32 Leaf::Leaf() 33 {} 34 35 Leaf::~Leaf() 36 {} 37 38 void Leaf::Operation() 39 { 40 cout<< "Leaf::Operation" <<endl; 41 } 42 43 Composite::Composite() 44 { 45 } 46 47 Composite::~Composite() 48 {} 49 50 void Composite::Add(Component* com) 51 { 52 this->m_ComVec.push_back(com); 53 } 54 55 void Composite::Remove(Component* com) 56 { 57 this->m_ComVec.erase(&com); 58 } 59 60 void Composite::Operation() 61 { 62 cout << "Composite::Operation" << endl; 63 vector<Component*>::iterator iter = this->m_ComVec.begin(); 64 for(;iter!= this->m_ComVec.end();iter++) 65 { 66 (*iter)->Operation(); 67 } 68 } 69 70 Component* Composite::GetChild(int index) 71 { 72 if(index < 0 || index > this->m_ComVec.size()) 73 { 74 return NULL; 75 } 76 return this->m_ComVec[index]; 77 }
main.cpp對象
1 #include "Composite.h" 2 #include <iostream> 3 4 using namespace std; 5 6 int main() 7 { 8 /* 9 不論是葉子Leaf仍是Composite對象pRoot、pCom都實現了Operation接口,因此能夠一致對待,直接調用Operation() 10 體現了「使得用戶對單個對象和組合對象的使用具備一致性。」 11 */ 12 Composite* pRoot = new Composite(); 13 14 //組合對象添加葉子節點 15 pRoot->Add(new Leaf()); 16 17 Leaf* pLeaf1 = new Leaf(); 18 Leaf* pLeaf2 = new Leaf(); 19 20 //這裏的葉子再添加葉子是沒有意義的。 21 //因爲葉子與組合對象繼承了相同的接口,因此語法上是對的,實際上什麼也沒作(繼承自基類Component的Add方法)。 22 //葉子節點只實現了Operation方法,其餘Add、Remove、GetChild都繼承自基類,沒有實際意義。 23 pLeaf1->Add(pLeaf2); 24 pLeaf1->Remove(pLeaf2); 25 //執行葉子Operation操做 26 pLeaf1->Operation(); 27 28 //組合對象實現了基類Component的全部接口,因此能夠作各類操做(Add、Remove、GetChild、Operation)。 29 Composite* pCom = new Composite(); 30 //組合對象添加葉子節點 31 pCom->Add(pLeaf1); 32 //組合對象添加葉子節點 33 pCom->Add(pLeaf2); 34 //執行組合對象Operation操做 35 pCom->Operation(); 36 37 //組合對象添加組合對象 38 pRoot->Add(pCom); 39 40 //執行組合對象Operation操做 41 pRoot->Operation(); 42 43 //Component* cp = pCom->GetChild(0); 44 //cp->Operation(); 45 46 //pCom->Remove(pLeaf1); 47 48 return 0; 49 }
組合的另外一個例子:摘自http://blog.csdn.net/wuzhekai1985/article/details/6667564
DP書上給出的定義:將對象組合成樹形結構以表示「部分-總體」的層次結構。組合使得用戶對單個對象和組合對象的使用具備一致性。注意兩個字「樹形」。這種樹形結構在現實生活中隨處可見,好比一個集團公司,它有一個母公司,下設不少家子公司。不論是母公司仍是子公司,都有各自直屬的財務部、人力資源部、銷售部等。對於母公司來講,不管是子公司,仍是直屬的財務部、人力資源部,都是它的部門。整個公司的部門拓撲圖就是一個樹形結構。
下面給出組合模式的UML圖。從圖中能夠看到,FinanceDepartment、HRDepartment兩個類做爲葉結點,所以沒有定義添加函數。而ConcreteCompany類能夠做爲中間結點,因此能夠有添加函數。那麼怎麼添加呢?這個類中定義了一個鏈表,用來放添加的元素。
相應的代碼實現爲:
1 class Company 2 { 3 public: 4 Company(string name) { m_name = name; } 5 virtual ~Company(){} 6 virtual void Add(Company *pCom){} 7 virtual void Show(int depth) {} 8 protected: 9 string m_name; 10 }; 11 //具體公司 12 class ConcreteCompany : public Company 13 { 14 public: 15 ConcreteCompany(string name): Company(name) {} 16 virtual ~ConcreteCompany() {} 17 void Add(Company *pCom) { m_listCompany.push_back(pCom); } //位於樹的中間,能夠增長子樹 18 void Show(int depth) 19 { 20 for(int i = 0;i < depth; i++) 21 cout<<"-"; 22 cout<<m_name<<endl; 23 list<Company *>::iterator iter=m_listCompany.begin(); 24 for(; iter != m_listCompany.end(); iter++) //顯示下層結點 25 (*iter)->Show(depth + 2); 26 } 27 private: 28 list<Company *> m_listCompany; 29 }; 30 //具體的部門,財務部 31 class FinanceDepartment : public Company 32 { 33 public: 34 FinanceDepartment(string name):Company(name){} 35 virtual ~FinanceDepartment() {} 36 virtual void Show(int depth) //只需顯示,無限添加函數,由於已經是葉結點 37 { 38 for(int i = 0; i < depth; i++) 39 cout<<"-"; 40 cout<<m_name<<endl; 41 } 42 }; 43 //具體的部門,人力資源部 44 class HRDepartment :public Company 45 { 46 public: 47 HRDepartment(string name):Company(name){} 48 virtual ~HRDepartment() {} 49 virtual void Show(int depth) //只需顯示,無限添加函數,由於已經是葉結點 50 { 51 for(int i = 0; i < depth; i++) 52 cout<<"-"; 53 cout<<m_name<<endl; 54 } 55 };
客戶使用方式:
1 int main() 2 { 3 Company *root = new ConcreteCompany("總公司"); 4 Company *leaf1=new FinanceDepartment("財務部"); 5 Company *leaf2=new HRDepartment("人力資源部"); 6 root->Add(leaf1); 7 root->Add(leaf2); 8 9 //分公司A 10 Company *mid1 = new ConcreteCompany("分公司A"); 11 Company *leaf3=new FinanceDepartment("財務部"); 12 Company *leaf4=new HRDepartment("人力資源部"); 13 mid1->Add(leaf3); 14 mid1->Add(leaf4); 15 root->Add(mid1); 16 //分公司B 17 Company *mid2=new ConcreteCompany("分公司B"); 18 FinanceDepartment *leaf5=new FinanceDepartment("財務部"); 19 HRDepartment *leaf6=new HRDepartment("人力資源部"); 20 mid2->Add(leaf5); 21 mid2->Add(leaf6); 22 root->Add(mid2); 23 root->Show(0); 24 25 delete leaf1; delete leaf2; 26 delete leaf3; delete leaf4; 27 delete leaf5; delete leaf6; 28 delete mid1; delete mid2; 29 delete root; 30 return 0; 31 }
上面的實現方式有缺點,就是內存的釋放很差,須要客戶本身動手,很是不方便。有待改進,比較好的作法是讓ConcreteCompany類來釋放。由於全部的指針都是存在ConcreteCompany類的鏈表中。C++的麻煩,沒有垃圾回收機制。上面的實現方式有缺點,就是內存的釋放很差,須要客戶本身動手,很是不方便。有待改進,比較好的作法是讓ConcreteCompany類來釋放。由於全部的指針都是存在ConcreteCompany類的鏈表中。C++的麻煩,沒有垃圾回收機制。