C++設計模式——組合模式

問題描述

上圖,是一個公司的組織結構圖,總部下面有多個子公司,同時總部也有各個部門,子公司下面有多個部門。若是對這樣的公司開發一個OA系統,做爲程序員的你,如何設計這個OA系統呢?先不說如何設計實現,接着往下看,看完了下面的內容,再回過頭來想怎麼設計這樣的OA系統。ios

 

什麼是組合模式?

在GOF的《設計模式:可複用面向對象軟件的基礎》一書中對組合模式是這樣說的:將對象組合成樹形結構以表示「部分-總體」的層次結構。組合(Composite)模式使得用戶對單個對象和組合對象的使用具備一致性。程序員

組合模式(Composite)將小對象組合成樹形結構,使用戶操做組合對象如同操做一個單個對象。組合模式定義了「部分-總體」的層次結構,基本對象能夠被組合成更大的對象,並且這種操做是可重複的,不斷重複下去就能夠獲得一個很是大的組合對象,但這些組合對象與基本對象擁有相同的接口,於是組合是透明的,用法徹底一致。設計模式

咱們這樣來簡單的理解組合模式,組合模式就是把一些現有的對象或者元素,通過組合後組成新的對象,新的對象提供內部方法,可讓咱們很方便的完成這些元素或者內部對象的訪問和操做。咱們也能夠把組合對象理解成一個容器,容器提供各類訪問其內部對象或者元素的API,咱們只須要使用這些方法就能夠操做它了。函數

UML類圖

Component:spa

  1. 爲組合中的對象聲明接口;
  2. 在適當的狀況下,實現全部類共有接口的缺省行爲;
  3. 聲明一個接口用於訪問和管理Component的子組件。

Leaf:設計

  1. 在組合中表示葉節點對象,葉節點沒有子節點;
  2. 在組合中定義葉節點的行爲。

Composite:3d

  1. 定義有子部件的那些部件的行爲;
  2. 存儲子部件。

Client:code

經過Component接口操做組合部件的對象。對象

 

代碼實現

 1 #include <iostream>
 2 #include <string>
 3 #include <vector>
 4 using namespace std;  5 // 抽象的部件類描述未來全部部件共有的行爲
 6 class Component  7 {  8 public:  9      Component(string name) : m_strCompname(name){}  10      virtual ~Component(){}  11      virtual void Operation() = 0;  12      virtual void Add(Component *) = 0;  13      virtual void Remove(Component *) = 0;  14      virtual Component *GetChild(int) = 0;  15      virtual string GetName()  16  {  17           return m_strCompname;  18  }  19      virtual void Print() = 0;  20 protected:  21      string m_strCompname;  22 };  23 class Leaf : public Component  24 {  25 public:  26      Leaf(string name) : Component(name)  27  {}  28      void Operation()  29  {  30           cout<<"I'm "<<m_strCompname<<endl;  31  }  32      void Add(Component *pComponent){}  33      void Remove(Component *pComponent){}  34      Component *GetChild(int index)  35  {  36           return NULL;  37  }  38      void Print(){}  39 };  40 class Composite : public Component  41 {  42 public:  43      Composite(string name) : Component(name)  44  {}  45      ~Composite()  46  {  47           vector<Component *>::iterator it = m_vecComp.begin();  48           while (it != m_vecComp.end())  49  {  50                if (*it != NULL)  51  {  52                     cout<<"----delete "<<(*it)->GetName()<<"----"<<endl;  53                     delete *it;  54                     *it = NULL;  55  }  56  m_vecComp.erase(it);  57                it = m_vecComp.begin();  58  }  59  }  60      void Operation()  61  {  62           cout<<"I'm "<<m_strCompname<<endl;  63  }  64      void Add(Component *pComponent)  65  {  66  m_vecComp.push_back(pComponent);  67  }  68      void Remove(Component *pComponent)  69  {  70           for (vector<Component *>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)  71  {  72                if ((*it)->GetName() == pComponent->GetName())  73  {  74                     if (*it != NULL)  75  {  76                          delete *it;  77                          *it = NULL;  78  }  79  m_vecComp.erase(it);  80                     break;  81  }  82  }  83  }  84      Component *GetChild(int index)  85  {  86           if (index > m_vecComp.size())  87  {  88                return NULL;  89  }  90           return m_vecComp[index - 1];  91  }  92      void Print()  93  {  94           for (vector<Component *>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)  95  {  96                cout<<(*it)->GetName()<<endl;  97  }  98  }  99 private: 100      vector<Component *> m_vecComp; 101 }; 102 int main(int argc, char *argv[]) 103 { 104      Component *pNode = new Composite("Beijing Head Office"); 105      Component *pNodeHr = new Leaf("Beijing Human Resources Department"); 106      Component *pSubNodeSh = new Composite("Shanghai Branch"); 107      Component *pSubNodeCd = new Composite("Chengdu Branch"); 108      Component *pSubNodeBt = new Composite("Baotou Branch"); 109      pNode->Add(pNodeHr); 110      pNode->Add(pSubNodeSh); 111      pNode->Add(pSubNodeCd); 112      pNode->Add(pSubNodeBt); 113      pNode->Print(); 114      Component *pSubNodeShHr = new Leaf("Shanghai Human Resources Department"); 115      Component *pSubNodeShCg = new Leaf("Shanghai Purchasing Department"); 116      Component *pSubNodeShXs = new Leaf("Shanghai Sales department"); 117      Component *pSubNodeShZb = new Leaf("Shanghai Quality supervision Department"); 118      pSubNodeSh->Add(pSubNodeShHr); 119      pSubNodeSh->Add(pSubNodeShCg); 120      pSubNodeSh->Add(pSubNodeShXs); 121      pSubNodeSh->Add(pSubNodeShZb); 122      pNode->Print(); 123      // 公司不景氣,須要關閉上海質量監督部門
124      pSubNodeSh->Remove(pSubNodeShZb); 125      if (pNode != NULL) 126  { 127           delete pNode; 128           pNode = NULL; 129  } 130      return 0; 131 }

 

實現要點

  1. Composite的關鍵之一在於一個抽象類,它既能夠表明Leaf,又能夠表明Composite;因此在實際實現時,應該最大化Component接口,Component類應爲Leaf和Composite類儘量多定義一些公共操做。Component類一般爲這些操做提供缺省的實現,而Leaf和Composite子類能夠對它們進行重定義;
  2. Component是否應該實現一個Component列表,在上面的代碼中,我是在Composite中維護的列表,因爲在Leaf中,不可能存在子Composite,因此在Composite中維護了一個Component列表,這樣就減小了內存的浪費;
  3. 內存的釋放;因爲存在樹形結構,當父節點都被銷燬時,全部的子節點也必須被銷燬,因此,我是在析構函數中對維護的Component列表進行統一銷燬,這樣就能夠免去客戶端頻繁銷燬子節點的困擾;
  4. 因爲在Component接口提供了最大化的接口定義,致使一些操做對於Leaf節點來講並不適用,好比:Leaf節點並不能進行Add和Remove操做,因爲Composite模式屏蔽了部分與總體的區別,爲了防止客戶對Leaf進行非法的Add和Remove操做,因此,在實際開發過程當中,進行Add和Remove操做時,須要進行對應的判斷,判斷當前節點是否爲Composite。

 

組合模式的優勢

將對象組合成樹形結構以表示「部分-總體」的層次結構。組合模式使得用戶對單個對象和組合對象的使用具備一致性。blog

 

使用場景

  1. 你想表示對象的部分-總體層次結構;
  2. 但願用戶忽略組合對象與單個對象的不一樣,用戶將統一地使用組合結構中的全部對象。

引用大話設計模式的片斷:「當發現需求中是體現部分與總體層次結構時,以及你但願用戶能夠忽略組合對象與單個對象的不一樣,統一地使用組合結構中的全部對象時,就應該考慮組合模式了。」

 

總結

經過上面的簡單講解,咱們知道了,組合模式意圖是經過總體與局部之間的關係,經過樹形結構的形式進行組織複雜對象,屏蔽對象內部的細節,對外展示統一的方式來操做對象,是咱們處理更復雜對象的一個手段和方式。如今再結合上面的代碼,想一想文章開頭提出的公司OA系統如何進行設計。

相關文章
相關標籤/搜索