C++設計模式-Composite組合模式

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++的麻煩,沒有垃圾回收機制。

相關文章
相關標籤/搜索