树形结构在软件中随处可见,比如操作系统中的目录结构,公司组织结构等等,如何运用面向对象的方式来处理这种树形结构是组合模式需要解决的问题。组合模式通过一种巧妙的设计方案来使得用户可以一致性地处理整个树形结构或者树形结构的一部分,也可以一致地处理树形结构中的叶子节点(不包含子节点的节点)和容器节点(包含子节点的节点).

一 组合模式简介

1.1 模式概述

组合(Composite)模式:组合多个对象形成树形结构以表示具有“整体-部分”关系的层次结构。组合模式对单个对象(即叶子对象)和组合对象(即容器对象)的使用具有一致性,组合模式又可以称为“部分-整体”(Part-Whole)模式,它是一种对象结构型模式。  

1.2 需求介绍

M公司开发部想要开发一个杀毒软件,该软件既可以针对某个文件夹杀毒,也可以针对某个指定的文件进行杀毒。该杀毒软件还可以根据各类文件的特点,为不同类型的文件提供不同的杀毒方式,例如图像文件(ImageFile)和文本文件(TextFile)的杀毒方式就有所差异。现需要提供该杀毒软件的整体框架设计方案。

二 杀毒软件框架设计

  首先在D盘创建如下树结构:

  

2.1 类图

  

2.2 代码实现

2.2.1 抽象文件类

#pragma once

#include <vector>
#include <map> #include <iostream>
using namespace std; // 抽象文件管理类
class CAbsFile
{
public:
CAbsFile(){}
virtual ~CAbsFile(){} virtual void AddFile(CAbsFile *pFile)
{
m_FileVect.push_back(pFile);
} virtual void RemoveFile(string strFileName)
{
vector<CAbsFile*>::iterator iter;
for (iter= m_FileVect.begin(); iter != m_FileVect.end(); iter ++)
{
if ( == strFileName.compare((*iter)->m_strFileName))
{
m_FileVect.erase(iter);
}
}
} virtual CAbsFile* GetChild(string strFileName)
{
vector<CAbsFile*>::iterator iter;
for (iter= m_FileVect.begin(); iter != m_FileVect.end(); iter ++)
{
if ( == strFileName.compare((*iter)->m_strFileName))
{
return *iter;
}
} return NULL;
} virtual void PrintFileStruct()
{
cout << m_strFileName.c_str() <<endl;
vector<CAbsFile*>::iterator iter;
for (iter= m_FileVect.begin(); iter != m_FileVect.end(); iter ++)
{
CAbsFile *pFile = *iter;
pFile->PrintFileStruct();
}
} virtual void DeleteObject()
{
vector<CAbsFile*>::iterator iter;
for (iter= m_FileVect.begin(); iter != m_FileVect.end(); iter ++)
{
CAbsFile *pFile = *iter;
pFile->DeleteObject();
} delete this;
}
virtual void KillVirus() = ; public:
vector<CAbsFile*> m_FileVect;
string m_strFileName;
};

2.2.2 具体text文件类

class CTextFile : public CAbsFile
{
public:
CTextFile(string strFileName)
{
m_strFileName = strFileName;
cout << "CTextFile Construct" << endl;
} ~CTextFile()
{
cout << "CTextFile Deconstruct" << endl;
} void KillVirus()
{
cout << "对文本文件:" << m_strFileName.c_str() << "进行杀毒操作" << endl;
}
};

2.2.3 具体img文件类

class CImgFile : public CAbsFile
{
public:
CImgFile(string strFileName)
{
m_strFileName = strFileName;
cout << "CImgFile Construct" << endl;
} ~CImgFile()
{
cout << "CImgFile Deconstruct" << endl;
} void KillVirus()
{
cout << "对图像文件:" << m_strFileName.c_str() << "进行杀毒操作" << endl;
}
};

2.2.4 具体文件夹类

class CFolder : public CAbsFile
{
public:
CFolder(string strFileName)
{
m_strFileName = strFileName;
cout << "CFolder Construct" << endl;
} ~CFolder()
{
cout << "CFolder Deconstruct" << endl;
} void KillVirus()
{
cout << "对文件夹:" << m_strFileName.c_str() << "进行杀毒操作" << endl;
vector<CAbsFile*>::iterator iter;
for (iter= m_FileVect.begin(); iter != m_FileVect.end(); iter ++)
{
CAbsFile *pFile = *iter;
pFile->KillVirus();
}
}
};

2.3 代码测试

#include "stdio.h"

#include "compose.h"

void main()
{
// 创建文件对象
cout << "创建文件对象" << endl;
CAbsFile *pFolderD = new CFolder("本地磁盘D");
CAbsFile *pFolderComposeTest = new CFolder("ComposeTest");
CAbsFile *pFolderImgFiles = new CFolder("ImgFiles");
CAbsFile *pFolderTextFiles = new CFolder("TextFiles");
CAbsFile *pImgFile = new CImgFile("Image.png");
CAbsFile *pTextFile = new CTextFile("1.txt"); // 构建文件组合
pFolderImgFiles->AddFile(pImgFile);
pFolderTextFiles->AddFile(pTextFile);
pFolderComposeTest->AddFile(pFolderImgFiles);
pFolderComposeTest->AddFile(pFolderTextFiles);
pFolderD->AddFile(pFolderComposeTest);
// 打印文件夹结构
cout << "打印本地磁盘D文件结构" << endl;
pFolderD->PrintFileStruct();
cout <<endl;
// 对composeTest文件夹进程杀毒操作
cout << "对composeTest文件夹进程杀毒操作" << endl;
pFolderComposeTest->KillVirus();
cout << endl; // 对单个img文件进行杀毒操作
cout << "对单个img文件进行杀毒操作" << endl;
pImgFile->KillVirus();
cout <<endl; cout << "释放文件对象" << endl;
pFolderD->DeleteObject();
return;
}

  在具体实现时,可以创建图形界面让用户自己选择所需操作的根节点,无需修改源代码,符合开闭原则,客户端无须关心节点的层次结构,可以对所选节点进行统一处理,提高系统的灵活性。

三 组合模式小结

3.1 主要优点

  (1)可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使客户忽略了层次的差异,方便对整个层次结构进行控制。

  (2)增加新的容器构件和叶子构件都十分方便,无需对现有类库代码进行任何修改,符合开闭原则

  (3)为树形结构的面向对象实现提供了灵活地解决方案,可以形成复杂的树形结构,但对树形结构的控制却很简单

3.2 主要缺点

  增加新构件时很难对容器中的构建类型进行限制。

3.3 适用场景

  (1)在具有整体和部分的层次结构中,希望通过一种方式忽略整体与部分的差异,客户端可以一致地对待他们。

  (2)在一个使用面向对象语言开发的系统中需要处理一个树形结构。

设计模式之组合(compose)模式的更多相关文章

  1. C++设计模式实现--组合(Composite)模式

    一. 举例 这个样例是书上的,如果有一个公司的组结结构例如以下: 它的结构非常像一棵树,当中人力资源部和財务部是没有子结点的,详细公司才有子结点. 并且最关健的是,它的每一层结构非常相似. 代码实现例 ...

  2. Head First 设计模式 —— 11. 组合 (Composite) 模式

    思考题 我们不仅仅要支持多个菜单,升值还要支持菜单中的菜单.你如何处理这个新的设计需求? P355 [提示]在我们的新设计中,真正需要以下三点: P354 我们需要某种属性结构,可以容纳菜单.子菜单和 ...

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

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

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

    今天研究了一下设计模式15 组合模式 本人是菜鸟一枚,所以一开始完全不懂组合究竟是什么意思.先上图一张,树形结构图: 文档说,如果想做出这样的结构,通常考虑组合模式.那是为什么呢?现在让我们看一下组合 ...

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

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

  6. php设计模式七 ---组合模式

    1.介绍 组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结 ...

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

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

  8. Java进阶篇设计模式之六 ----- 组合模式和过滤器模式

    前言 在上一篇中我们学习了结构型模式的外观模式和装饰器模式.本篇则来学习下组合模式和过滤器模式. 组合模式 简介 组合模式是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来 ...

  9. 设计模式のCompositePattern(组合模式)----结构模式

    一.产生背景 又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象.组合模式依据树形结构来组合对象,用来表示部分以及整体层次.这种类型的设计模式属于结构型模式,它创建了对象组的树形结构. 这种模 ...

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

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

随机推荐

  1. Java并发之Semaphore的使用

    Java并发之Semaphore的使用 一.简介 今天突然发现,看着自己喜欢的球队发挥如此的棒,然后写着博客,这种感觉很爽.现在是半场时间,就趁着这个时间的空隙,说说Java并发包中另外一个重量级的类 ...

  2. Linux安全策略配置-pam_tally2身份验证模块

    PAM身份验证安全配置实例 - 强制使用强密码(用户密码安全配置) - 用户SSH登录失败尝试次数超出限制后锁定账户(帐户锁定/解锁和时间设置) - 允许普通用户使用sudo而不是su(限制普通用户登 ...

  3. Linux x86架构下ACPI PNP Hardware ID的识别机制

    转:https://blog.csdn.net/morixinguan/article/details/79343578 关于Hardware ID的用途,在前面已经大致的解释了它的用途,以及它和AC ...

  4. MyEclipse激活失败

    最近从MyEclipse2014升级MyEclipse2015,结果按照MyEclipse2014的方式激活2015总是失败,显示错误如下图所示: 反复实验,怎么也不能成功激活,最终找到方法 很多情况 ...

  5. Qt性能问题

    使用Qt库开发通信上位机软件,如串口.CAN总线等,涉及到接收界面高速刷新,会使CPU消耗率过高(20%以上),可能还会卡顿. 具体原因不知道,突然想放弃Qt了 ps: 1.问题出在界面刷新,会占据C ...

  6. 2 Powershell与Cmd以及Unix/Linux Shell

    上篇文章我说道,windows为了改变用户对其console界面的诟病,于是就从windows   vista开始,计划要改变这种局面,于是就有 了Powershell的出现. 1.兼容shell命令 ...

  7. Swift学习笔记 - 位移枚举的按位或运算

    在OC里面我们经常遇到一些枚举值可以多选的,需要用或运算来把这些枚举值链接起来,这样的我们称为位移枚举,但是在swift里面却不能这么做,下面来讲解一下如何在swift里面使用 OC的位移枚举的区分 ...

  8. centos7 -lvm卷组

    老忘,记一下   基本的逻辑卷管理概念: PV(Physical Volume)- 物理卷 物理卷在逻辑卷管理中处于最底层,它可以是实际物理硬盘上的分区,也可以是整个物理硬盘,也可以是raid设备. ...

  9. NumPy矩阵库

    NumPy - 矩阵库 NumPy 包包含一个 Matrix库numpy.matlib.此模块的函数返回矩阵而不是返回ndarray对象. matlib.empty() matlib.empty()函 ...

  10. Java socket - 使用代理服务器

    为什么使用代理服务器不需要多说了. 使用Proxy Java提供了Proxy类实现使用代理进行通信. Proxy类的构造器Proxy(Proxy.Type type, SocketAddress sa ...