C++设计模式之组合模式

 更新时间:2014年09月30日 16:16:15   作者:果冻想  
这篇文章主要介绍了C++设计模式之组合模式,本文讲解什么是组合模式、组合模式的优点、组合模式实例等内容,需要的朋友可以参考下

问题描述

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

什么是组合模式?

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

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

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

UML类图

Component:

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

Leaf:

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

Composite:

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

Client:

3.通过Component接口操作组合部件的对象。

代码实现

复制代码 代码如下:

/*
** FileName     : CompositePatternDemo
** Author       : Jelly Young
** Date         : 2013/12/09
** Description  : More information, please go to https://www.jb51.net
*/
#include <iostream>
#include <string>
#include <vector>
using namespace std;
// 抽象的部件类描述将来所有部件共有的行为
class Component
{
public:
     Component(string name) : m_strCompname(name){}
     virtual ~Component(){}
     virtual void Operation() = 0;
     virtual void Add(Component *) = 0;
     virtual void Remove(Component *) = 0;
     virtual Component *GetChild(int) = 0;
     virtual string GetName()
     {
          return m_strCompname;
     }
     virtual void Print() = 0;
protected:
     string m_strCompname;
};
class Leaf : public Component
{
public:
     Leaf(string name) : Component(name)
     {}
     void Operation()
     {
          cout<<"I'm "<<m_strCompname<<endl;
     }
     void Add(Component *pComponent){}
     void Remove(Component *pComponent){}
     Component *GetChild(int index)
     {
          return NULL;
     }
     void Print(){}
};
class Composite : public Component
{
public:
     Composite(string name) : Component(name)
     {}
     ~Composite()
     {
          vector<Component *>::iterator it = m_vecComp.begin();
          while (it != m_vecComp.end())
          {
               if (*it != NULL)
               {
                    cout<<"----delete "<<(*it)->GetName()<<"----"<<endl;
                    delete *it;
                    *it = NULL;
               }
               m_vecComp.erase(it);
               it = m_vecComp.begin();
          }
     }
     void Operation()
     {
          cout<<"I'm "<<m_strCompname<<endl;
     }
     void Add(Component *pComponent)
     {
          m_vecComp.push_back(pComponent);
     }
     void Remove(Component *pComponent)
     {
          for (vector<Component *>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
          {
               if ((*it)->GetName() == pComponent->GetName())
               {
                    if (*it != NULL)
                    {
                         delete *it;
                         *it = NULL;
                    }
                    m_vecComp.erase(it);
                    break;
               }
          }
     }
     Component *GetChild(int index)
     {
          if (index > m_vecComp.size())
          {
               return NULL;
          }
          return m_vecComp[index - 1];
     }
     void Print()
     {
          for (vector<Component *>::iterator it = m_vecComp.begin(); it != m_vecComp.end(); ++it)
          {
               cout<<(*it)->GetName()<<endl;
          }
     }
private:
     vector<Component *> m_vecComp;
};
int main(int argc, char *argv[])
{
     Component *pNode = new Composite("Beijing Head Office");
     Component *pNodeHr = new Leaf("Beijing Human Resources Department");
     Component *pSubNodeSh = new Composite("Shanghai Branch");
     Component *pSubNodeCd = new Composite("Chengdu Branch");
     Component *pSubNodeBt = new Composite("Baotou Branch");
     pNode->Add(pNodeHr);
     pNode->Add(pSubNodeSh);
     pNode->Add(pSubNodeCd);
     pNode->Add(pSubNodeBt);
     pNode->Print();
     Component *pSubNodeShHr = new Leaf("Shanghai Human Resources Department");
     Component *pSubNodeShCg = new Leaf("Shanghai Purchasing Department");
     Component *pSubNodeShXs = new Leaf("Shanghai Sales department");
     Component *pSubNodeShZb = new Leaf("Shanghai Quality supervision Department");
     pSubNodeSh->Add(pSubNodeShHr);
     pSubNodeSh->Add(pSubNodeShCg);
     pSubNodeSh->Add(pSubNodeShXs);
     pSubNodeSh->Add(pSubNodeShZb);
     pNode->Print();
     // 公司不景气,需要关闭上海质量监督部门
     pSubNodeSh->Remove(pSubNodeShZb);
     if (pNode != NULL)
     {
          delete pNode;
          pNode = NULL;
     }
     return 0;
}

实现要点

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

相关文章

  • 深入二叉树两个结点的最低共同父结点的详解

    深入二叉树两个结点的最低共同父结点的详解

    本篇文章是对二叉树两个结点的最低共同父结点进行了详细的分析介绍,需要的朋友参考下
    2013-05-05
  • C语言实现简单的井字棋游戏

    C语言实现简单的井字棋游戏

    这篇文章主要为大家详细介绍了C语言实现简单的井字棋游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-04-04
  • 浅析c/c++中函数的参数传递

    浅析c/c++中函数的参数传递

    c/c++中,函数可以传递的参数有三种形式,值、引用和指针。以下分别对这三种形式进行了介绍,需要的朋友可以过来参考下
    2013-07-07
  • C语言利用栈实现对后缀表达式的求解

    C语言利用栈实现对后缀表达式的求解

    这篇文章主要为大家详细介绍了C语言利用栈实现对后缀表达式的求解,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-04-04
  • C语言实现简易扫雷小游戏

    C语言实现简易扫雷小游戏

    这篇文章主要为大家详细介绍了C语言实现简易扫雷小游戏,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-10-10
  • C语言编程C++旋转字符操作串示例详解

    C语言编程C++旋转字符操作串示例详解

    这篇文章主要为大家介绍了C语言编程中C++旋转字符操作串示例详解,文中附含详细图文示例代码,有需要的朋友可以借鉴参考下,希望能够有所帮助
    2021-09-09
  • 浅析C#与C++相关概念的比较

    浅析C#与C++相关概念的比较

    以下是对C#与C++的相关概念进行了比较和介绍。需要的朋友可以过来参考下
    2013-08-08
  • C++中实现队列类链式存储与栈类链式存储的代码示例

    C++中实现队列类链式存储与栈类链式存储的代码示例

    这篇文章主要介绍了C++中实现队列类链式存储与栈类链式存储的代码示例,通过注释来说明,直接上代码,简单粗暴XD 需要的朋友可以参考下
    2016-03-03
  • c++模拟实现string类详情

    c++模拟实现string类详情

    这篇文章主要介绍了c++模拟实现string类详情,string表示可变长的字符序列,使用string类型必须首先包含string头文件。作为标准库的一部分,string定义在命名空间std中,下面进入文章一起看看详细内容吧
    2022-01-01
  • C++编写高性能服务器实例教程

    C++编写高性能服务器实例教程

    这篇文章主要介绍了如何用C++编写高性能服务器,文中通过示例代码介绍的非常详细,对大家学习C++有一定的参考价值,需要的朋友们可以了解下
    2020-06-06

最新评论