zoukankan      html  css  js  c++  java
  • C++设计模式——组合模式

    问题描述

    上图,是一个公司的组织结构图,总部下面有多个子公司,同时总部也有各个部门,子公司下面有多个部门。如果对这样的公司开发一个OA系统,作为程序员的你,如何设计这个OA系统呢?先不说如何设计实现,接着往下看,看完了下面的内容,再回过头来想怎么设计这样的OA系统。

     

    什么是组合模式?

    在GOF的《设计模式:可复用面向对象软件的基础》一书中对组合模式是这样说的:将对象组合成树形结构以表示“部分-整体”的层次结构。组合(Composite)模式使得用户对单个对象和组合对象的使用具有一致性。

    组合模式(Composite)将小对象组合成树形结构,使用户操作组合对象如同操作一个单个对象。组合模式定义了“部分-整体”的层次结构,基本对象可以被组合成更大的对象,而且这种操作是可重复的,不断重复下去就可以得到一个非常大的组合对象,但这些组合对象与基本对象拥有相同的接口,因而组合是透明的,用法完全一致。

    我们这样来简单的理解组合模式,组合模式就是把一些现有的对象或者元素,经过组合后组成新的对象,新的对象提供内部方法,可以让我们很方便的完成这些元素或者内部对象的访问和操作。我们也可以把组合对象理解成一个容器,容器提供各种访问其内部对象或者元素的API,我们只需要使用这些方法就可以操作它了。

    UML类图

    Component:

    1. 为组合中的对象声明接口;
    2. 在适当的情况下,实现所有类共有接口的缺省行为;
    3. 声明一个接口用于访问和管理Component的子组件。

    Leaf:

    1. 在组合中表示叶节点对象,叶节点没有子节点;
    2. 在组合中定义叶节点的行为。

    Composite:

    1. 定义有子部件的那些部件的行为;
    2. 存储子部件。

    Client:

    通过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。

     

    组合模式的优点

    将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

     

    使用场景

    1. 你想表示对象的部分-整体层次结构;
    2. 希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象。

    引用大话设计模式的片段:“当发现需求中是体现部分与整体层次结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式了。”

     

    总结

    通过上面的简单讲解,我们知道了,组合模式意图是通过整体与局部之间的关系,通过树形结构的形式进行组织复杂对象,屏蔽对象内部的细节,对外展现统一的方式来操作对象,是我们处理更复杂对象的一个手段和方式。现在再结合上面的代码,想想文章开头提出的公司OA系统如何进行设计。

  • 相关阅读:
    Android_方向传感器
    Android 网络图片查看器与网页源码查看器
    SQLite数据库_实现简单的增删改查
    Android 解析JSON
    多线程
    并发编程
    幂等性
    Django缓存机制
    计算机基础
    RESTful规范
  • 原文地址:https://www.cnblogs.com/ring1992/p/9593013.html
Copyright © 2011-2022 走看看