博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
设计模式之组合模式
阅读量:5255 次
发布时间:2019-06-14

本文共 8283 字,大约阅读时间需要 27 分钟。

2018-09-20 16:12:07

组合模式(Composite)

  组合模式(Composite),将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象(即叶子构件)和组合对象(即组合构件)的使用具有一致性。(例如,你可以在word里对单个字和一行字采用同样的操作)注意,这里说的树就是一颗树,没有任何的限制,它可以是任何形状的。这棵树它是靠对象之间的组合关系构建起来,而非数据结构意义上的树。

何时使用组合模式

  当你发现需求中是体现部分整体层次的结构(树状结构)时,以及你希望用户可以忽略组合对象与单个对象的不同,统一的使用组合结构中的所有对象时,就应该考虑组合模式了。

组合模式UML类图

组合模式根据实现的不同可以分为两种:透明方式组合模式、安全方式组合模式

透明方式组合模式UML类图:

   在透明组合模式中,Component是应用了组合模式的所有构件的基类,它提供了整个模式结构中所有子类的公共方法,另外提供了用于管理以及访问子构件的方法(例如Add、Remove、GetChild)

  Leaf在这个结构中表示叶子结点,就像数据结构中的树一样,叶子结点不能有子节点。所以很明显的问题是,叶子结点实现用于管理子构件的方法:Add、Remove、GetChild毫无意义。这个就是透明组合模式存在的问题。

  Composite:在它的内部有一个包含Component指针对象的列表,因为在整个模式中,Composite表示的是一个分支结点,分支结点下又可能有数量不定的分支结点,这个列表的作用就是保存分支结点的子节点用的。在Composite中实现了用于管理子节点的方法:Add、Remove、GetChild。

  透明组合模式的好处在于,对client来说屏蔽了叶子节点和分支结点的差异。但client必须要明确的知道哪个是叶子结点,否则在使用上可能会出现一些问题。

安全组合模式UML类图

 

  从上图可以看出安全组合模式和透明组合模式最大的差别就是Component基类不再具有所有子类的方法,这样Leaf就不必实现一些不必要的方法了,例如对分支结点的管理方法。

 

组合模式的优缺点

优点:

  1.组合模式可以清楚的定义分层次的复杂对象,表示对象的全部或部分层次。

  2.当用户希望忽略组合对象和单个对象的不同时,采用组合模式,提高了软件的可复用性。因此此时,client代码可以一致的使用组合结构或者其中的单个对象。

  3.在组合结构中,添加新的节点或者叶子是一件很容易的事情。因为每个子类都提供了对它所拥有的构建进行管理的能力,所以此时无需对原有的类进行修改。

  4.为树形结构提供了一种灵活的解决方案,通过递归组合叶子和分支结点可以组合出结构复杂的树,但同时client代码对树的管理的复杂度不会提高。

缺点:

  增大了设计难度。在进行设计时你需要先抽象出整个树的结构,区分清楚哪些应该是叶子,但问题在于不是所有的结点都必须会和叶子有关联。

代码示例

  模仿文件系统:文件系统中有两类文件,一种是目录(文件夹)、另外一种就是普通文件,目录下可以包含目录也可以包含普通文件,当时普通文件下是不能包含任何类型的文件的。整个文件系统构成了一个树形结构。既然普通文件和目录都是文件,那么我们可以抽象出一个文件基类。另外,由普通文件下不能再包含任何类型文件可知,普通文件是目录树一个分支上的节点。接下来我们来模拟一下这个树形的文件系统。

透明组合模式

1.抽象出一个文件和文件夹的基类:

#ifndef COMPONENT_H_#define COMPONENT_H_#include 
class Component{public: virtual void add(Component *value) = 0; virtual void remove(Component *value) = 0; virtual Component* getChild(const int iIndex) = 0; virtual void displayOwnInfo(const int depth) const = 0; Component() = default; virtual ~Component() = default;protected: std::string m_strName;};#endif
Component

2.普通文件类 (Leaf)

#ifndef LEAF_H_#define LEAF_H_// This is a ordinary File class#include "Component.h"#include 
class Leaf : public Component{public: void add(Component* value) override; void remove(Component *value) override; Component* getChild(const int iIndex) override; void displayOwnInfo(const int depth) const override; Leaf(const std::string strName) { m_strName = strName; } ~Leaf() = default;};#endif#include "Leaf.h"void Leaf::add(Component* value){ std::cout << "I am just a Leaf,There is nothing to do!" << std::endl;}void Leaf::remove(Component* value){ std::cout << "I am just a Leaf.This is nothing to do!" << std::endl;}Component* Leaf::getChild(const int iIndex){ std::cout << "I am just a Leaf.There is nothing to do!" << std::endl; return nullptr;}void Leaf::displayOwnInfo(const int depth) const{ std::string strOut('+',depth); std::cout << strOut << m_strName<<".I am a Leaf(Ordinary File)" <
Leaf

3.目录类(Composite)

#ifndef COMPOSITE_H_#define COMPOSITE_H_#include "Component.h"#include 
#include
class Composite:public Component{public: void add(Component *value); void remove(Component *value); Component* getChild(const int iIndex); void displayOwnInfo(const int depth) const; Composite(const std::string strName) { m_strName = strName; } ~Composite(); Composite() = delete;private: std::vector
m_vecComponent;};#endif#include "Composite.h"void Composite::add(Component *value){ m_vecComponent.push_back(value);}void Composite::remove(Component *value){ auto iter = m_vecComponent.begin(); while(iter != m_vecComponent.end()) { if(*iter == value) { if(nullptr != *iter) { delete value; value = nullptr; m_vecComponent.erase(iter); break; } } ++iter; }}Component* Composite::getChild(const int iIndex){ if(iIndex <0 || iIndex >= m_vecComponent.size()) return nullptr; return m_vecComponent[iIndex];}void Composite::displayOwnInfo(const int depth) const{ std::string strOut('+',depth); std::cout << strOut << m_strName << "I am a Dir!" << std::endl; for(auto it : m_vecComponent) { it->displayOwnInfo(depth+2); }}Composite::~Composite(){ for(auto it : m_vecComponent) { if(it != nullptr) { delete it; it = nullptr; } }}
View Code

4.客户端(client)

#include "Composite.h"#include "Leaf.h"using namespace std;int main(int argc,char *argv[]){    //Create a Tree    //Create a Root Node    Composite *pRoot = new Composite("Root");    //Create a Leaf    Leaf *pIniFile = new Leaf("Ini.txt");    pRoot->add(pIniFile);    //Remove Leaf    pRoot->remove(pIniFile);    //Create a Branch    Composite *p2Level = new Composite("2Level");    Leaf *p2LevelLeaf1 = new Leaf("2LevelLeaf1");    p2Level->add(p2LevelLeaf1);    Composite *p3Level = new Composite("3Level");    Leaf *p3LevelLeaf1 = new Leaf("3LevelLeaf1");    p3Level->add(p3LevelLeaf1);    p2Level->add(p3Level);    pRoot->add(p2Level);            pRoot->displayOwnInfo(1);    return (1);}
View Code

安全组合模式

  透明组合模式中的不安全,其实就是说叶子结点中多了它不该有的操作——对分支结点进行管理的方法,例如add、remove、getChild。要想使它安全,那么最简单的办法就是把这些方法从公共基类里剔除,延迟到Composite类里去声明和实现,这样分支结点和叶子结点就不会有不安全的因素了。

1.抽象出普通文件和目录文件的基类(UML图中的Component)

#ifndef COMPONENT_H_#define COMPONENT_H_#include 
class Component{public: virtual void displayOwnInfo(const int depth) const = 0; Component() = default; virtual ~Component() = default;protected: std::string m_strName;};#endif
Component

2.普通文件类(UML类图中的Leaf)

#ifndef LEAF_H_#define LEAF_H_// This is a ordinary File class#include "Component.h"#include 
class Leaf : public Component{public: void displayOwnInfo(const int depth) const override; Leaf(const std::string strName) { m_strName = strName; } ~Leaf() = default;};#endif#include "Leaf.h"void Leaf::displayOwnInfo(const int depth) const{ std::string strOut(depth,'+'); std::cout << strOut << m_strName<<".I am a Leaf(Ordinary File)" <
Leaf

3.目录文件类(UML类图中的Composite)

#ifndef COMPOSITE_H_#define COMPOSITE_H_#include "Component.h"#include 
#include
class Composite:public Component{public: void add(Component *value); void remove(Component *value); Component* getChild(const int iIndex); void displayOwnInfo(const int depth) const; Composite(const std::string strName) { m_strName = strName; } ~Composite(); Composite() = delete;private: std::vector
m_vecComponent;};#endif#include "Composite.h"void Composite::add(Component *value){ m_vecComponent.push_back(value);}void Composite::remove(Component *value){ auto iter = m_vecComponent.begin(); while(iter != m_vecComponent.end()) { if(*iter == value) { if(nullptr != *iter) { delete value; value = nullptr; m_vecComponent.erase(iter); break; } } ++iter; }}Component* Composite::getChild(const int iIndex){ if(iIndex <0 || iIndex >= m_vecComponent.size()) return nullptr; return m_vecComponent[iIndex];}void Composite::displayOwnInfo(const int depth) const{ std::string strOut(depth,'+'); std::cout << strOut << m_strName << "I am a Dir!" << std::endl; for(auto it : m_vecComponent) { it->displayOwnInfo(depth+2); }}Composite::~Composite(){ for(auto it : m_vecComponent) { if(it != nullptr) { delete it; it = nullptr; } }}
Composite

4.main函数(UML类图中的Client)

#include "Composite.h"#include "Leaf.h"using namespace std;int main(int argc,char *argv[]){    //Create a Tree    //Create a Root Node    Composite *pRoot = new Composite("Root");    //Create a Leaf    Leaf *pIniFile = new Leaf("Ini.txt");    pRoot->add(pIniFile);    //Remove Leaf    pRoot->remove(pIniFile);    //Create a Branch    Composite *p2Level = new Composite("2Level");    Leaf *p2LevelLeaf1 = new Leaf("2LevelLeaf1");    p2Level->add(p2LevelLeaf1);    Composite *p3Level = new Composite("3Level");    Leaf *p3LevelLeaf1 = new Leaf("3LevelLeaf1");    p3Level->add(p3LevelLeaf1);    p2Level->add(p3Level);    pRoot->add(p2Level);            pRoot->displayOwnInfo(1);    return (1);}
Client

 

转载于:https://www.cnblogs.com/ToBeExpert/p/9682277.html

你可能感兴趣的文章
blogs
查看>>
Remove Duplicates from Sorted List II
查看>>
Win10《芒果TV》商店版更新v3.2.5:新增会员频道,修复多处细节问题,小年快乐...
查看>>
SpringBoot jar 注册windows服务
查看>>
OC4_NSString操作
查看>>
合并二维数组,并计算重复字段的平均值
查看>>
第六章部分例题 双向bfs邻接表和邻接矩阵实现
查看>>
求100内的数和
查看>>
【tyvj】【搜索】小猫爬山
查看>>
QT+信号有参数与无参数的实现+QT4和QT5在信号和槽使用上的区别
查看>>
Android混淆代码
查看>>
一个常见的错误时编写代码
查看>>
如何估算内存的消耗
查看>>
Android 驱动(二) IIC简单介绍
查看>>
Oracle 11g client的安装和配置。
查看>>
STM32低功耗总结
查看>>
jquery技巧之让任何组件都支持类似DOM的事件管理
查看>>
Java IO 5 : 对象序列化
查看>>
《降龙之剑》刷马坐标 BOSS坐标,鉴定出好马的时间段
查看>>
Python_格式化输出、基本运算符、初始编码
查看>>