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系统如何进行设计。

相关文章
相关标签/搜索