[C++设计模式] composite 组合模式

组合(Composite)模式的其它翻译名称也很多,比如合成模式、树模式等等。在《设计模式》一书中给出的定义是:将对象以树形结构组织起来,以达成“部分-整体”的层次结构,使得客户端对单个对象和组合对象的使用具有一致性。

从定义中可以得到使用组合模式的环境为:在设计中想表示对象的“部分-整体”层次结构;希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象。

看下组合模式的组成。

1)         抽象构件角色Component:它为组合中的对象声明接口,也可以为共有接口实现缺省行为。

2)       树叶构件角色Leaf:在组合中表示叶节点对象——没有子节点,实现抽象构件角色声明的接口。

3)       树枝构件角色Composite:在组合中表示分支节点对象——有子节点,实现抽象构件角色声明的接口;存储子部件。

Component:

为组合中的对象声明接口;

在适当的情况下,实现所有类共有接口的缺省行为;

声明一个接口用于访问和管理Component的子组件。

Leaf:

在组合中表示叶节点对象,叶节点没有子节点;

在组合中定义叶节点的行为。

Composite:

定义有子部件的那些部件的行为;

存储子部件。

Client:

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

组合模式中必须提供对子对象的管理方法,不然无法完成对子对象的添加删除等等操作,也就失去了灵活性和扩展性。但是管理方法是在Component中就声明还是在Composite中声明呢?

一种方式是在Component里面声明所有的用来管理子类对象的方法,以达到Component接口的最大化(如下图所示)。目的就是为了使客户看来在接口层次上树叶和分支没有区别——透明性。但树叶是不存在子类的,因此Component声明的一些方法对于树叶来说是不适用的。这样也就带来了一些安全性问题。

另一种方式就是只在Composite里面声明所有的用来管理子类对象的方法(如下图所示)。这样就避免了上一种方式的安全性问题,但是由于叶子和分支有不同的接口,所以又失去了透明性。

《设计模式》一书认为:在这一模式中,相对于安全性,我们比较强调透明性。对于第一种方式中叶子节点内不需要的方法可以使用空处理或者异常报告的方式来解决。

#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;
}

Composite的关键之一在于一个抽象类,它既可以代表Leaf,又可以代表Composite;所以在实际实现时,应该最大化Component接口,Component类应为Leaf和Composite类尽可能多定义一些公共操作。Component类通常为这些操作提供缺省的实现,而Leaf和Composite子类可以对它们进行重定义;

Component是否应该实现一个Component列表,在上面的代码中,我是在Composite中维护的列表,由于在Leaf中,不可能存在子Composite,所以在Composite中维护了一个Component列表,这样就减少了内存的浪费;

内存的释放;由于存在树形结构,当父节点都被销毁时,所有的子节点也必须被销毁,所以,我是在析构函数中对维护的Component列表进行统一销毁,这样就可以免去客户端频繁销毁子节点的困扰;

由于在Component接口提供了最大化的接口定义,导致一些操作对于Leaf节点来说并不适用,比如:Leaf节点并不能进行Add和Remove操作,由于Composite模式屏蔽了部分与整体的区别,为了防止客户对Leaf进行非法的Add和Remove操作,所以,在实际开发过程中,进行Add和Remove操作时,需要进行对应的判断,判断当前节点是否为Composite。

版权声明:本文为博主原创文章,未经博主允许不得转载。

时间: 2024-10-16 11:04:49

[C++设计模式] composite 组合模式的相关文章

设计模式08: Composite 组合模式(结构型模式)

Composite 组合模式(结构型模式) 对象容器的问题在面向对象系统中,我们常会遇到一类具有“容器”特征的对象——即他们在充当对象的同时,又是其他对象的容器. public interface IBox { void Process(); } public class SingleBox:IBox { public void Process(){...} } public class ContainerBox:IBox { public void Process(){...} public

设计模式之组合模式(Composite)摘录

23种GOF设计模式一般分为三大类:创建型模式.结构型模式.行为模式. 创建型模式抽象了实例化过程,它们帮助一个系统独立于如何创建.组合和表示它的那些对象.一个类创建型模式使用继承改变被实例化的类,而一个对象创建型模式将实例化委托给另一个对象.创建型模式有两个不断出现的主旋律.第一,它们都将关于该系统使用哪些具体的类的信息封装起来.第二,它们隐藏了这些类的实例是如何被创建和放在一起的.整个系统关于这些对象所知道的是由抽象类所定义的接口.因此,创建型模式在什么被创建,谁创建它,它是怎样被创建的,以

设计模式(九):Composite组合模式 -- 结构型模式

1. 概述 在数据结构里面,树结构是很重要,我们可以把树的结构应用到设计模式里面. 例子1:就是多级树形菜单. 例子2:文件和文件夹目录 2.问题 我们可以使用简单的对象组合成复杂的对象,而这个复杂对象有可以组合成更大的对象.我们可以把简单这些对象定义成类,然后定义一些容器类来存储这些简单对象.客户端代码必须区别对象简单对象和容器对象,而实际上大多数情况下用户认为它们是一样的.对这些类区别使用,使得程序更加复杂.递归使用的时候跟麻烦,而我们如何使用递归组合,使得用户不必对这些类进行区别呢? 3.

设计模式之组合模式(Composite)

1.定义 组合模式(Composite Pattern)也叫合成模式,将对象组合成树形结构以表示"整体-部分"的层次结构,使得用户对单个对象和组合对象的使用具有一致性. 2.通用类图 Component抽象构件角色:定义参加组合对象的共有方法和属性,可以定义一些默认的行为或属性. Leaf叶子构件:叶子对象,其下再也没有其他的分支,也就是遍历的最小单位. Composite树枝构件:树枝对象,它的作用是组合树枝节点和叶子节点形成一个树形结构. 3.通用源代码 package Compo

C#设计模式:组合模式(Composite Pattern)

一,C#设计模式:组合模式(Composite Pattern) using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; namespace _9.组合模式 { //组合模式主要用来处理一类具有"容器特征"的对象--即它们在充当对象的同时,又可以作为容器包含其他多个对象. //组合模式,将对象组合成树形结构以表示

C#设计模式(10)——组合模式(Composite Pattern)

一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象和复合对象在功能上区别,导致在操作过程中必须区分简单对象和复合对象,这样就会导致客户调用带来不必要的麻烦,然而作为客户,它们希望能够始终一致地对待简单对象和复合对象.然而组合模式就是解决这样的问题.下面让我们看看组合模式是怎样解决这个问题的. 二.组合模式的详细介绍 2.1 组合模式的定义 组合模式

图解Java设计模式之组合模式

图解Java设计模式之组合模式 看一个学校院系展示需求 传统方案解决学院院系展示(类图) 传统方案解决学校院系展示存在的问题分析 组合模式基本介绍 组合模式的原理类图 组合模式解决学校院系展示的应用实例 组合模式在JDK集合的源码分析 组合模式的注意事项和细节 看一个学校院系展示需求 编写程序展示一个学校院系结构 :需求是这样,要在一个页面中展示出学校的院系组成,一个学校有多个学院,一个学院有多个系.如图 : 传统方案解决学院院系展示(类图) 传统方案解决学校院系展示存在的问题分析 1)将学院看

设计模式之组合模式

当需求中是体现部分与整体层次的结构时,以及你希望忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑使用组合模式了.例如:我们单个复制一个文件和多个复制文件,对我们而言,并不在乎一个文件的复制与多个文件复制的区别,也就是我们的操作是一样的. 下面的代码是建立一个公司的组织结构,其中各个部分,不管是分公司还是部门,都拥有一套相同的功能操作. 代码如下: using System; using System.Collections.Generic; using System.L

c++设计模式15 --组合模式

今天研究了一下设计模式15 组合模式 本人是菜鸟一枚,所以一开始完全不懂组合究竟是什么意思.先上图一张,树形结构图: 文档说,如果想做出这样的结构,通常考虑组合模式.那是为什么呢?现在让我们看一下组合模式的类图一本结构 想了很久,结合源代码,才搞明白,其实这个组合,意思就是说,如果我们要做这种树状结果,比如公司想让我们吧所有部门人员的 姓名,职位,薪水遍历出来,这个时候怎么办呢?那我们看树状机构图,有叶子结点和枝干结点,2种,但是2种有共性,那就是每个结点都有姓名,职位,薪水.所有叶子结点和枝干