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

news/2025/2/12 17:03:50/

组合模式 (Composite)

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


意图

  • 将对象组合成树形结构,以表示“部分-整体”的层次结构。
  • 使得客户端可以以一致的方式处理单个对象和对象的组合。

使用场景

  1. 需要表示部分与整体的层次结构

    • 如文件系统、组织架构等。
  2. 客户端需要以一致的方式处理单个对象和组合对象

    • 统一处理方式简化了客户端的代码逻辑。

参与者角色

  1. 组件 (Component)

    • 定义了组合对象和叶子对象的公共接口。
  2. 叶子 (Leaf)

    • 表示层次结构的叶子节点,没有子节点。
  3. 组合 (Composite)

    • 表示层次结构中的非叶子节点,存储子节点,并实现与子节点相关的操作。
  4. 客户端 (Client)

    • 通过组件接口与对象的组合结构交互,无需关心对象是叶子还是组合对象。

示例代码

以下代码展示了如何使用组合模式实现文件系统的层次结构。

#include <iostream>
#include <vector>
#include <string>// 组件接口:定义叶子和组合对象的公共接口
class FileSystemComponent {
public:virtual ~FileSystemComponent() = default;virtual void display(int indent = 0) const = 0; // 显示组件内容的接口virtual void add(FileSystemComponent* component) {throw std::runtime_error("Cannot add to a leaf component.");}virtual void remove(FileSystemComponent* component) {throw std::runtime_error("Cannot remove from a leaf component.");}
};// 叶子类:文件
class File : public FileSystemComponent {
private:std::string name;public:File(const std::string& fileName) : name(fileName) {}void display(int indent = 0) const override {std::cout << std::string(indent, ' ') << "- File: " << name << std::endl;}
};// 组合类:目录
class Directory : public FileSystemComponent {
private:std::string name;std::vector<FileSystemComponent*> children; // 存储子节点public:Directory(const std::string& dirName) : name(dirName) {}~Directory() {for (auto child : children) {delete child;}}void display(int indent = 0) const override {std::cout << std::string(indent, ' ') << "+ Directory: " << name << std::endl;for (const auto& child : children) {child->display(indent + 2);}}void add(FileSystemComponent* component) override {children.push_back(component);}void remove(FileSystemComponent* component) override {children.erase(std::remove(children.begin(), children.end(), component), children.end());delete component;}
};// 客户端代码
int main() {// 创建目录和文件Directory* root = new Directory("root");Directory* subDir1 = new Directory("subDir1");Directory* subDir2 = new Directory("subDir2");File* file1 = new File("file1.txt");File* file2 = new File("file2.txt");File* file3 = new File("file3.txt");// 构建文件系统结构root->add(subDir1);root->add(subDir2);subDir1->add(file1);subDir1->add(file2);subDir2->add(file3);// 显示文件系统结构root->display();// 清理内存delete root;return 0;
}

代码解析

1. 组件接口 (FileSystemComponent)
  • 定义了叶子和组合对象的公共接口,所有对象必须实现 display 方法。
  • 提供了默认的 addremove 方法,叶子类中默认抛出异常。
class FileSystemComponent {
public:virtual ~FileSystemComponent() = default;virtual void display(int indent = 0) const = 0;virtual void add(FileSystemComponent* component) {throw std::runtime_error("Cannot add to a leaf component.");}virtual void remove(FileSystemComponent* component) {throw std::runtime_error("Cannot remove from a leaf component.");}
};
2. 叶子类 (File)
  • 表示树结构的叶子节点,例如文件。叶子节点没有子节点。
class File : public FileSystemComponent {
private:std::string name;public:File(const std::string& fileName) : name(fileName) {}void display(int indent = 0) const override {std::cout << std::string(indent, ' ') << "- File: " << name << std::endl;}
};
3. 组合类 (Directory)
  • 表示树结构的非叶子节点,例如目录。组合对象可以包含叶子节点和其他组合对象。
  • 提供 addremove 方法,用于添加或移除子节点。
class Directory : public FileSystemComponent {
private:std::string name;std::vector<FileSystemComponent*> children;public:Directory(const std::string& dirName) : name(dirName) {}~Directory() {for (auto child : children) {delete child;}}void display(int indent = 0) const override {std::cout << std::string(indent, ' ') << "+ Directory: " << name << std::endl;for (const auto& child : children) {child->display(indent + 2);}}void add(FileSystemComponent* component) override {children.push_back(component);}void remove(FileSystemComponent* component) override {children.erase(std::remove(children.begin(), children.end(), component), children.end());delete component;}
};
4. 客户端
  • 客户端通过 FileSystemComponent 接口与文件系统交互,不需要关心具体是叶子对象还是组合对象。
Directory* root = new Directory("root");
Directory* subDir1 = new Directory("subDir1");
File* file1 = new File("file1.txt");root->add(subDir1);
subDir1->add(file1);
root->display(); // 显示文件系统结构

优缺点

优点
  1. 统一接口
    • 客户端可以以一致的方式处理单个对象和组合对象。
  2. 灵活性高
    • 可以很容易地扩展新类型的叶子节点或组合对象。
  3. 简化客户端代码
    • 客户端不需要了解对象的具体类型,简化了代码逻辑。
缺点
  1. 可能导致系统复杂性增加
    • 如果对象种类较多,系统会变得更加复杂。
  2. 对子节点的管理较难
    • 子节点的添加和删除操作可能需要额外的逻辑。

适用场景

  1. 需要表示部分与整体的层次结构

    • 如图形系统中的图形组件、文件系统中的目录和文件。
  2. 客户端需要统一对待单个对象和组合对象


总结

组合模式通过将对象组合成树形结构,使得客户端能够统一地处理单个对象和组合对象,特别适用于表示部分-整体层次结构的场景。


http://www.ppmy.cn/news/1564637.html

相关文章

3d系统误差分析

系统标定重投影误差预估 在计算机视觉和三维重建领域中&#xff0c;评估一个相机系统标定精度的重要指标。通过比较真实的三维点在图像中的投影位置与标定模型计算出的投影位置之间的差异&#xff0c;来衡量标定的准确性。 以下是对这一概念的详细解析&#xff1a; 什么是系统…

多种 Docker 镜像拉取解决方案与实践

最近国内 Docker 镜像拉取不太通畅&#xff0c;尝试了几种镜像拉取的方式&#xff0c;写篇博客分享一下。 原以为只是 docker hub 被毙了&#xff0c;上机器一操作&#xff0c;官方的下载地址也被毙了&#xff0c;真是从源头解决问题。 不过还好目前还有其他源能用&#xff0…

Kubernetes 部署 RabbitMQ 集群教程

本文介绍如何在 Kubernetes 中部署 RabbitMQ 集群&#xff0c;包含从命名空间创建到配置 NFS 存储的详细步骤。 参考文档&#xff1a; RabbitMQ 集群部署NFS StorageClass 创建 部署步骤 1. 创建命名空间 kubectl create ns rabbitmq2. 创建 RBAC 权限 创建文件 rabbitmq…

【神经网络基础】

目录 一、神经网络的构成 1.1什么是神经网络&#xff1f; 1.2 激活函数 1.2.1 Sigmoid 1.2.2 Tanh 1.2.3 ReLU 1.2.4 softmax 1.2.5 其他激活函数 1.2.6 选择激活函数 1.3 参数初始化 1.4 模型构建 二、损失函数 2.1 分类问题 2.1.1多分类&#xff08;多分类交叉…

如何微调本地大模型构建私有知识库

如何微调本地大模型构建私有知识库 在如今的信息化时代&#xff0c;数据是企业最宝贵的资产之一&#xff0c;而如何高效地管理和利用这些数据&#xff0c;成为了提升竞争力的关键。构建私有知识库是提升企业运营效率的有效手段&#xff0c;而微调本地大模型则成为了实现这一目…

Linux UDP 编程详解

一、引言 在网络编程领域&#xff0c;UDP&#xff08;User Datagram Protocol&#xff0c;用户数据报协议&#xff09;作为一种轻量级的传输层协议&#xff0c;具有独特的优势和适用场景。与 TCP&#xff08;Transmission Control Protocol&#xff0c;传输控制协议&#xff0…

正则表达式(python版最全面,最易懂)

正则表达式 正则表达式英文称regular expression 定义&#xff1a;正则表达式是一种文本模式匹配的工具&#xff0c;用于字符串的搜索&#xff0c;匹配和替换。在excel,word以及其他的文本编辑器都可直接适配。 一、基本匹配规则 字面值字符&#xff1a;例如字母、数字、空格…

jenkins docker 遇到 /var/run/docker.sock: permission denied 解决方案

使用 Jenkins Docker 会碰到 /var/run/docker.sock:/var/run/docker.sock: permission denied 这个错误&#xff0c;最暴力的解决方式就是放大限 777。比较优雅的解决方式是将 jenkins 加到 docker 组中。 groupadd -g 999 docker usermod -aG docker jenkins那个 gid 一定要保…