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

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

文章目录

    • 一、组合模式的介绍
    • 二、组合模式的结构
    • 三、示例代码

一、组合模式的介绍

  组合模式是一种结构型设计模式, 它将对象组合成树形结构以表示“整体-部分”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

换句话说:

  • 可以把“一个对象”和“多个对象的组合”统一对待。
  • 客户端代码不需要区分处理的是“叶子节点”还是“容器节点”。

二、组合模式的结构

组合模式一般包含以下角色:

  • 抽象组件(Component):定义了对象的通用接口,比如 add、remove、display 等。
  • 叶子节点(Leaf):表示最小的个体对象,没有子节点。
  • 组合节点(Composite):作为容器,可以包含叶子节点和其他组合节点,实现了 add、remove 等方法。
  • 客户端(Client):通过组件接口与对象交互,不关心是叶子还是组合。

在这里插入图片描述
优点:

  • 统一了叶子节点和组合节点的接口,客户端使用简单。
  • 可以方便地扩展树结构(新增叶子或组合类)。
  • 符合“开闭原则”。

缺点:

  • 设计更复杂,需要抽象类/接口。
  • 在层次较深时,可能影响性能。

使用场景:

  • 文件系统(文件夹和文件)。
  • GUI 界面(窗口中包含按钮、文本框等)。
  • 公司组织架构(部门、员工)。
  • 游戏中的场景树(节点包含子节点)。

三、示例代码

假设我们要表示一个文件夹-文件系统:

#include <iostream>
#include <vector>
#include <memory>
using namespace std;// 抽象组件
class FileSystemNode {
public:virtual void show(int depth = 0) const = 0;virtual ~FileSystemNode() = default;
};// 叶子节点:文件
class File : public FileSystemNode {string name;
public:File(const string& n) : name(n) {}void show(int depth = 0) const override {cout << string(depth, '-') << "File: " << name << endl;}
};// 组合节点:文件夹
class Folder : public FileSystemNode {string name;vector<shared_ptr<FileSystemNode>> children;
public:Folder(const string& n) : name(n) {}void add(shared_ptr<FileSystemNode> node) {children.push_back(node);}void show(int depth = 0) const override {cout << string(depth, '-') << "Folder: " << name << endl;for (auto& child : children) {child->show(depth + 2);}}
};// 客户端
int main() {auto root = make_shared<Folder>("root");auto folder1 = make_shared<Folder>("docs");auto folder2 = make_shared<Folder>("images");auto file1 = make_shared<File>("a.txt");auto file2 = make_shared<File>("b.txt");auto file3 = make_shared<File>("photo.jpg");folder1->add(file1);folder1->add(file2);folder2->add(file3);root->add(folder1);root->add(folder2);root->show();return 0;
}

Qt 组合模式示例:自定义 UI 组件树:
我们要实现一个抽象组件 UIComponent,它可以是 控件(叶子节点) 或 容器(组合节点,包含子控件),最终在 Qt 界面上展示。

#include <QApplication>
#include <QWidget>
#include <QPushButton>
#include <QVBoxLayout>
#include <QString>
#include <QDebug>// 抽象组件
class UIComponent {
public:virtual QWidget* widget() = 0; // 返回 Qt 控件virtual void add(UIComponent* comp) { Q_UNUSED(comp); } // 默认不实现virtual ~UIComponent() = default;
};// 叶子节点:具体控件(比如按钮)
class UIButton : public UIComponent {QPushButton* m_button;
public:UIButton(const QString& text) {m_button = new QPushButton(text);}QWidget* widget() override {return m_button;}
};// 组合节点:容器(比如垂直布局的 QWidget)
class UIContainer : public UIComponent {QWidget* m_widget;QVBoxLayout* m_layout;
public:UIContainer(const QString& title = "") {m_widget = new QWidget;m_layout = new QVBoxLayout(m_widget);if (!title.isEmpty()) {m_widget->setWindowTitle(title);}}void add(UIComponent* comp) override {m_layout->addWidget(comp->widget());}QWidget* widget() override {return m_widget;}
};// 客户端
int main(int argc, char *argv[]) {QApplication app(argc, argv);// 根容器UIContainer root("组合模式示例");// 子容器UIContainer* subContainer = new UIContainer;// 按钮(叶子节点)UIButton* btn1 = new UIButton("按钮 A");UIButton* btn2 = new UIButton("按钮 B");UIButton* btn3 = new UIButton("按钮 C");// 组合结构root.add(btn1);subContainer->add(btn2);subContainer->add(btn3);root.add(subContainer);// 显示root.widget()->show();return app.exec();
}

运行效果:

  • 主窗口标题为 组合模式示例。
  • 窗口中有一个按钮 A,以及一个子容器(里面放了按钮 B 和 C)。
  • 客户端代码完全不区分“按钮”还是“容器”,都通过 UIComponent* 统一管理。

思路说明:

  • UIComponent:抽象接口,类似 Component。
  • UIButton:叶子节点(单个控件)。
  • UIContainer:组合节点(内部有 QVBoxLayout,可以添加子节点)。
  • 客户端 main:只调用 add,不关心是按钮还是容器。
http://www.xdnf.cn/news/1381609.html

相关文章:

  • 【数据结构与算法】LeetCode 20.有效的括号
  • Vue 组件循环 简单应用及使用要点
  • 微服务保护和分布式事务-01.雪崩问题-原因分析
  • 步进电机、直流电机常见问题
  • APP手游使用游戏盾SDK为何能有效抵御各类攻击?
  • Java全栈工程师的实战面试:从基础到微服务的全面解析
  • 算法 --- 二分
  • Paimon——官网阅读:非主键表
  • CLIP图像特征提取:`CLIPVisionModel` vs `CLIPModel.get_image_features()`,哪种更适合你的任务?
  • [sys-BlueChi] docs | BluechiCtl命令行工具
  • 滑台模组如何实现电子制造精密加工?
  • Java 大视界 -- 基于 Java 的大数据实时流处理在智能电网分布式电源接入与电力系统稳定性维护中的应用(404)
  • 零基础开发应用:cpolar+Appsmith平民化方案
  • HVV面经总结(二)
  • MySQL事务ACID特性
  • 内网穿透工具【frp】的核心功能底层处理逻辑解析
  • Linux部分底层机制
  • LeetCode-279. 完全平方数
  • Linux 软件编程(十三)网络编程:TCP 并发服务器模型与 IO 多路复用机制、原理epoll
  • 工业机器人如何通过Modbus TCP转CanOpen网关高效通信!
  • HTML贪吃蛇游戏实现
  • RAW API 的 TCP 总结2
  • 鸿蒙Harmony-从零开始构建类似于安卓GreenDao的ORM数据库(四)
  • 刷题日记0828
  • 未来模型会转向多模态吗
  • Logstash数据迁移之mysql-to-kafka.conf详细配置
  • 领悟8种常见的设计模式
  • 导入文件允许合并表格
  • HBase Compaction HFile 可见性和并发安全性分析
  • audioMAE模型代码分析