当前位置: 首页 > news >正文

Chapter8—组合模式

组合模式

1 概念

组合模式是将部分对象组成树形结构,表示部分与整体之间的一种层次结构,整体包含部分,部分又由次级部分组成,这样的层次关系具有一致性。一个整体可以拆分出独立的模块或功能,这样独立的模块又可以继续拆分出类似的模块或功能,通过继承的方式将这些模块和功能按照层次关系组合成树形结构,在这个树形结构中,从根节点出发,遍历其所有的子节点进行处理,一视同仁的处理每个节点,忽略层次的差异,从而达到对整个系统进行处理。

2 意图(Intent)

将对象组合成树形结构以表示“部分-整体”的层次结构。Composite模式使得用户对单个对象和组合对象的使用具有一致性。简单工厂模式是指一个工厂对象通过其自身方法中的形参变量决定创建产品的类型。

3 动机(Motivate)

组合模式有时候又叫做部分-整体模式,它使我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以向处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦。

4 类图结构

在这里插入图片描述

5 角色定义

  • Component(组件接口):所有复合节点和叶子节点的高层抽象,定义出需要对组件操作的接口标准。

  • Composite(复合组件):包含多个子组件对象(可以是复合组件或叶端组件)的复合型组件,并实现组件接口中定义的操作方法。

  • Leaf(叶端组件):不包含子组件的终端组件,同样实现组件接口中定义的操作方法。

  • Client(客户端):按所需的层级关系部署相关对象并操作组件接口所定义的接口。

6 程序示例

文件列表

示例类图

在这里插入图片描述

基础节点类,也就是组件的接口类

/*** @brief 基础节点类*/
class BaseNode
{
public:BaseNode(const string& strName);virtual ~BaseNode() = default;public:virtual void Add(BaseNode* pChildNode) = 0;virtual void Display(int nSpace);                   // 展示本节点的内容virtual void Release() = 0;protected:string m_strName;
};BaseNode::BaseNode(const string &strName): m_strName(strName)
{// ...
}void BaseNode::Display(int nSpace)
{QString strSpace;for (int i = 0; i < nSpace; ++i)strSpace += " ";qDebug().noquote() << strSpace << m_strName.c_str();
}

文件夹类,也就是复合组件

/*** @brief 文件夹类*/
class Folder: public BaseNode
{
public:Folder(const string& strName);~Folder();public:void Add(BaseNode* pChildNode) override;void Display(int nSpace) override;void Release() override;private:vector<BaseNode*> m_vecChildNode;
};Folder::Folder(const string &strName): BaseNode(strName)
{}Folder::~Folder()
{qDebug() << "Folder Release!";
}void Folder::Add(BaseNode* pChildNode)
{m_vecChildNode.push_back(pChildNode);
}void Folder::Display(int nSpace)
{BaseNode::Display(nSpace);              // 调用父类接口先展示本目录名称,再遍历本目录里面的内容for (BaseNode* pNode : m_vecChildNode)pNode->Display(nSpace + 1);         // 子节点的空格需要+1, 这样显示一层层的效果
}void Folder::Release()
{for (BaseNode* pNode : m_vecChildNode)pNode->Release();                   // 先释放其子文件/目录delete this;                            // 再释放自己
}

文件夹类,也就是叶端组件类

/*** @brief 文件类*/
class File: public BaseNode
{
public:File(const string& strName);~File();public:void Add(BaseNode* pChildNode) override;void Release() override;
};File::File(const string &strName): BaseNode(strName)
{}File::~File()
{qDebug() << "File Release!";
}void File::Add(BaseNode* pChildNode)
{Q_UNUSED(pChildNode);
}void File::Release()
{delete this;
}

客户端使用场景

void ClientTest()
{BaseNode* pDriveD = new Folder("D:");BaseNode* pDoc = new Folder("Document");pDoc->Add(new File("Resume.doc"));pDoc->Add(new File("Project.ppt"));pDriveD->Add(pDoc);BaseNode* pMusic = new Folder("Movie");BaseNode* pHongKong = new Folder("HongKong");pHongKong->Add(new File("A.mp4"));pHongKong->Add(new File("B.mp4"));pHongKong->Add(new File("C.mp4"));BaseNode* pAmerica = new Folder("America");pAmerica->Add(new File("AA.mp4"));pAmerica->Add(new File("BB.mp4"));pMusic->Add(pHongKong);pMusic->Add(pAmerica);pDriveD->Add(pMusic);pDriveD->Display(0);pDriveD->Release();         // 释放内存
}

程序输出

 D:DocumentResume.docProject.pptMovieHongKongA.mp4B.mp4C.mp4AmericaAA.mp4BB.mp4File Release!
File Release!
Folder Release!
File Release!
File Release!
File Release!
Folder Release!
File Release!
File Release!
Folder Release!
Folder Release!
Folder Release!

水果盘

类图结构

在这里插入图片描述

抽象构建类MyElement(抽象类)

/*** @brief 抽象构建类MyElement(抽象类)*/
class MyElement
{
public:MyElement() = default;virtual ~MyElement() = default;public:virtual void Eat() = 0;virtual void Add(MyElement* pElement) = 0;virtual void Remove(MyElement* pElement) = 0;
};

叶子构建类Apple(苹果类)

/*** @brief 叶子构建类Apple(苹果类)*/
class Apple: public MyElement
{
public:Apple() = default;~Apple() = default;public:void Eat() override;void Add(MyElement* pElement) override;void Remove(MyElement* pElement) override;
};void Apple::Eat()
{qDebug() << "吃苹果!";
}void Apple::Add(MyElement *pElement)
{}void Apple::Remove(MyElement *pElement)
{}

叶子构建类Banana(香蕉类)

/*** @brief 叶子构建类Banana(香蕉类)*/
class Banana: public MyElement
{
public:Banana() = default;~Banana() = default;public:void Eat() override;void Add(MyElement* pElement) override;void Remove(MyElement* pElement) override;
};void Banana::Eat()
{qDebug() << "吃香蕉!";
}void Banana::Add(MyElement *pElement)
{}void Banana::Remove(MyElement *pElement)
{}

叶子构建类Pear(梨子类)

/*** @brief 叶子构建类Pear(梨子类)*/
class Pear: public MyElement
{
public:Pear() = default;~Pear() = default;public:void Eat() override;void Add(MyElement* pElement) override;void Remove(MyElement* pElement) override;
};void Pear::Eat()
{qDebug() << "吃梨子!";
}void Pear::Add(MyElement *pElement)
{}void Pear::Remove(MyElement *pElement)
{}

容器构建类Plate(水果盘类)

/*** @brief 容器构建类Plate(水果盘类)*/
class Plate: public MyElement
{
public:Plate() = default;~Plate() = default;public:void Eat() override;void Add(MyElement* pElement) override;void Remove(MyElement* pElement) override;private:vector<MyElement*> m_vecElement;
};void Plate::Eat()
{for (auto& pElement : m_vecElement)pElement->Eat();
}void Plate::Add(MyElement *pElement)
{m_vecElement.push_back(pElement);
}void Plate::Remove(MyElement *pElement)
{auto pFind = std::find(m_vecElement.begin(), m_vecElement.end(), pElement);if (pFind != m_vecElement.end())m_vecElement.erase(pFind);
}

测试函数

/*** @brief 测试函数*/
void ClientTest()
{MyElement* pAppleA = new Apple();MyElement* pPear = new Pear();MyElement* pPlateA = new Plate();pPlateA->Add(pAppleA);pPlateA->Add(pPear);MyElement* pBananaA = new Banana();MyElement* pBananaB = new Banana();MyElement* pPlateB = new Plate();pPlateB->Add(pBananaA);pPlateB->Add(pBananaB);MyElement* pAppleB = new Apple();MyElement* pPlateC = new Plate();pPlateC->Add(pPlateA);pPlateC->Add(pPlateB);pPlateC->Add(pAppleB);pPlateC->Eat();delete pAppleA;delete pPear;delete pPlateA;delete pBananaA;delete pBananaB;delete pPlateB;delete pAppleB;delete pPlateC;
}

7 思考小结

组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,使得增加新构建也很容易,因为它让客户忽略了层次的差异,而它的结构又是动态的,提供了对象管理的灵活接口,因此组合模式可以方便地对层次结构进行控制。组合模式定义了包含叶子对象和容器对象的类层次结构,叶子对象可以被组合成更复杂的容器对象,而这个容器对象又可以被组合,这样不断递归下去,可以形成复杂的树形结构。


文章转载自:

http://T97mZHKp.rkqkb.cn
http://sasQsE3p.rkqkb.cn
http://wS5y0H0Z.rkqkb.cn
http://4mHtX8bP.rkqkb.cn
http://Q54j7XAl.rkqkb.cn
http://RuzfFgqy.rkqkb.cn
http://n4SrXmxh.rkqkb.cn
http://Ovp0lABu.rkqkb.cn
http://fJ4JBVYo.rkqkb.cn
http://e7UyO7tm.rkqkb.cn
http://fciT8Ct2.rkqkb.cn
http://uuxqHMbi.rkqkb.cn
http://ZsD4DB9b.rkqkb.cn
http://L0hKtMDS.rkqkb.cn
http://Qc2YZcit.rkqkb.cn
http://wzRCjjrN.rkqkb.cn
http://cL7miGBt.rkqkb.cn
http://g53696rq.rkqkb.cn
http://pfNiP1ap.rkqkb.cn
http://MHgMZt8f.rkqkb.cn
http://M6rOK9hp.rkqkb.cn
http://Kccb8YD6.rkqkb.cn
http://X7iOmQGN.rkqkb.cn
http://wbs43szy.rkqkb.cn
http://5oDNXQx4.rkqkb.cn
http://YfMiyYio.rkqkb.cn
http://LtQ6dFKf.rkqkb.cn
http://aqDZWHJg.rkqkb.cn
http://6046kXhS.rkqkb.cn
http://mTb2k2oE.rkqkb.cn
http://www.dtcms.com/a/386964.html

相关文章:

  • vmware的ub系统长时间不动会黑屏
  • 从0到1打造一个能上传任意GeoJSON的交互式Web地图
  • 深入理解数据结构之复杂度
  • Silicon EFR32xG22 CMU
  • 运维面试笔记(持续补充版)
  • 托福阅读35-1
  • qt QCandlestickSet详解
  • 在Linux和Windows系统下使用Qt监测U盘的插拔事件
  • 文字识别接口的应用场景-发票识别接口-OCR API
  • 鸿蒙NEXT ArkWeb同层渲染:原生与Web的完美融合
  • 基于springboot的4s店汽车销售服务系统
  • ARM芯片的调试访问端口 DAP(Debug Access Port)
  • 减少推导式中的重复计算:赋值表达式(:=)的优雅应用 (Effective Python 第29条)
  • 空压机远程控制与数据采集的御控物联网解决方案
  • 瑞萨MCU RA4M1 FLASH锁死问题记录
  • Kubernetes 调度器(Scheduler)
  • Java设计模型-责任链模式
  • Linux 服务器安全优化:firewalld SSH 限制 白名单与 SCP 服务禁用流程
  • bisheng 智能体
  • 学完Python之后我写了一个免费看电影的软件
  • 【ROS2】Concept(Advanced )
  • Apifox自动化测试场景设计
  • 知识复用缺乏跨角色适配该如何改善
  • XML 与 YML 全方位对比:从语法到应用场景
  • pandas方法集
  • PAT乙级_1106 2019数列_Python_AC解法_含疑难点
  • 自动检测并交互删除未使用 Docker 自定义网桥
  • 物联网卡相关知识
  • 访答编辑器使用体验
  • 日常系统问题解决:数据库查询停止