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

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

看下组合模式的组成。

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

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

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

watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQv/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="">

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列表进行统一销毁,这样就能够免去client频繁销毁子节点的困扰。

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

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

  1. 一天一个设计模式——Composite组合模式

    一.模式说明 能够使容器与内容物具有一致性,创造出递归结构的模式就是Composite组合模式. 举个例子:计算机中的文件系统中有文件和文件夹的概念,我们知道,文件夹可以包含文件,也可以包含子文件夹, ...

  2. C++设计模式-Composite组合模式

    Composite组合模式作用:将对象组合成树形结构以表示“部分-整体”的层次结构.Composite使得用户对单个对象和组合对象的使用具有一致性. UML图如下: 在Component中声明所有用来 ...

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

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

  4. 乐在其中设计模式(C#) - 组合模式(Composite Pattern)

    原文:乐在其中设计模式(C#) - 组合模式(Composite Pattern) [索引页][源码下载] 乐在其中设计模式(C#) - 组合模式(Composite Pattern) 作者:weba ...

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

    一.引言 在软件开发过程中,我们经常会遇到处理简单对象和复合对象的情况,例如对操作系统中目录的处理就是这样的一个例子,因为目录可以包括单独的文件,也可以包括文件夹,文件夹又是由文件组成的,由于简单对象 ...

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

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

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

    一,C#设计模式:组合模式(Composite Pattern) using System; using System.Collections.Generic; using System.Linq; ...

  8. JavaScript设计模式之----组合模式

    javascript设计模式之组合模式 介绍 组合模式是一种专门为创建Web上的动态用户界面而量身制定的模式.使用这种模式可以用一条命令在多个对象上激发复杂的或递归的行为.这可以简化粘合性代码,使其更 ...

  9. 十一、Composite 组合模式

    原理: 代码清单 Entity public abstract class Entry { public abstract String getName(); public abstract int ...

随机推荐

  1. VC窗口类的销毁-是否需要delete

    Windows窗口如果使用new的方法添加之后,在父窗口析构的时候,有些需要delete有些却不需要delete.这个的确有点坑,由于c++的实现,对于每个自己new的对象,我都会delete删除它, ...

  2. 移动web——轮播图

    1.我们将5张图片又前后各增加一张,第一张前增加的是原本的第五张,第五张后增加的是原本的第一张,增加的原因无非是手指滑动的时候有轮播效果,这不像以前的轮播图,点击图标就能立刻将ul跳转到指定位置,手机 ...

  3. jenkins配置发送测试结果邮件

    简单版: https://www.cnblogs.com/gcgc/p/5631385.html https://blog.51cto.com/qicheng0211/1919341 升级版 http ...

  4. Vue中this.$router.push参数获取(通过路由传参)【路由跳转的方法】

    传递参数的方法: 1.Params 由于动态路由也是传递params的,所以在 this.$router.push() 方法中 path不能和params一起使用,否则params将无效.需要用nam ...

  5. Requests库 更新中

    1.获取网页内容 --- requests库 <需理解HTTP协议> >requests库的7个主要方法   方法 说明 requests.requests() 构造一个请求,支撑一 ...

  6. java基本类型和包装类型的区别以及object的公共方法

    Java的类型分为两部分,一个是基本类型(primitive),如int.double等八种基本数据类型: 一.基本数据类型: byte:Java中最小的数据类型,在内存中占8位(bit),即1个字节 ...

  7. CSS 选择器 知识点

    <html> <head> <style type="text/css"> h1 > strong { /*子元素选择器 只选择自己 的子 ...

  8. 【原创】基于NodeJS Express框架开发的一个VIP视频网站项目及源码分享

    项目名称:视频网站项目 开发语言:HTML,CSS(前端),JavaScript,NODEJS(expres)(后台) 数据库:MySQL 开发环境:Win7,Webstorm 上线部署环境:Linu ...

  9. P4047 [JSOI2010]部落划分(最小生成树)

    题目描述 聪聪研究发现,荒岛野人总是过着群居的生活,但是,并不是整个荒岛上的所有野人都属于同一个部落,野人们总是拉帮结派形成属于自己的部落,不同的部落之间则经常发生争斗.只是,这一切都成为谜团了——聪 ...

  10. HTML学习笔记之标签进阶

    目录 1.框架 2.表单 3.音频 4.视频 5.文档类型 6.头部元素 7.样式 8.脚本 9.实体 1.框架 使用框架允许我们在同一个浏览器窗口中显示多个页面,其中每份 HTML 文档称为一个框架 ...