09结构型设计模式——组合模式

一、组合模式的简介

组合模式(Composite Pattern)是一种结构型设计模式,主要用于处理树形结构中的对象组合问题。它允许你将对象组合成树形结构,以表示部分-整体层次结构。组合模式使得客户端能够统一地对待单个对象和对象组合,从而简化了树形结构的操作。

组合模式的结构图

  1. 组件(Component)

    • 定义了叶子节点和容器节点的共同接口或抽象类。通常包括一些通用的方法,例如operation(),这些方法会被叶子节点和容器节点实现。
  2. 叶子节点(Leaf)

    • 实现了组件接口的具体类,代表树形结构中的最底层元素。叶子节点没有子节点,它们实现了具体的操作逻辑。
  3. 容器节点(Composite)

    • 也实现了组件接口的具体类,代表树形结构中的中间节点。容器节点可以有子节点,这些子节点可以是叶子节点或其他容器节点。容器节点通常包含对子节点的管理功能,例如添加、删除子节点的方法。

组合模式的核心概念

  1. 对象的统一处理

    • 组合模式允许你将对象(叶子节点)和对象组合(容器节点)以相同的方式对待。这意味着客户端可以对叶子节点和容器节点使用相同的操作,而不必关心它们的具体类型。
  2. 部分-整体关系

    • 组合模式主要用于表示"部分"和"整体"之间的关系。整体由部分组成,而部分也可以是整体的一部分。通过这种方式,可以在树形结构中定义和管理层次关系。
  3. 递归结构

    • 组合模式常常使用递归结构,因为树形结构本质上是递归的。一个节点可能包含其他节点,而这些节点又可以包含更多节点。

组合模式的优点

  1. 统一处理

    • 客户端代码可以通过统一的接口处理单个对象和对象组合,从而简化了操作和维护。
  2. 简化代码

    • 组合模式可以将复杂的树形结构操作封装在组件类中,使得客户端代码更简洁、更易于理解。
  3. 灵活性

    • 可以在运行时动态地增加或修改树形结构中的节点。通过组合模式,可以灵活地构建和管理树形结构。
  4. 扩展性

    • 组合模式允许你在不修改现有代码的情况下,轻松地扩展新的节点类型或结构。

二、组合模式的应用场景

1. 文件系统

场景:操作文件和目录,文件系统本质上是一个树形结构,目录包含文件和子目录,子目录也可以包含文件和子目录。

2. 图形用户界面(GUI)

场景:构建图形用户界面时,界面元素(如按钮、文本框、面板)可以组成复杂的层次结构,面板中可以包含其他面板和各种控件。

3. 组织结构管理

场景:管理公司或组织的层级结构,包括员工、部门和公司。公司包含多个部门,每个部门包含员工或其他子部门。

4. 菜单系统

场景:构建复杂的菜单系统,包括菜单项、子菜单和子菜单项,菜单项和子菜单项可以统一处理。

5. 树形结构的数据处理

场景:处理复杂的数据结构,如解析和管理 XML 或 JSON 数据。这些数据结构通常具有嵌套的层次关系。

三、组合模式的设计方法

目录/文件的组合关系(目录包含目录,目录包含文件)

composite.cpp

cpp 复制代码
#include <iostream>
#include <vector>
#include <memory>
#include <string>

// 文件系统
class FileSystemComponent {
public:
    virtual ~FileSystemComponent() = default;
    virtual void list(int indent = 0) const = 0;
};

// 文件
class File : public FileSystemComponent {
public:
    File(const std::string& name) : name(name) {}
    void list(int indent = 0) const override {
        std::cout << std::string(indent, ' ') << "File: " << name << std::endl;
    }

private:
    std::string name;
};

// 目录
class Directory : public FileSystemComponent {
public:
    Directory(const std::string& name) : name(name) {}
    
    void add(std::shared_ptr<FileSystemComponent> component) {
        children.push_back(component);
    }

    void list(int indent = 0) const override {
        std::cout << std::string(indent, ' ') << "Directory: " << name << std::endl;
        for (const auto& child : children) {
            child->list(indent + 2);
        }
    }

private:
    std::string name;
    std::vector<std::shared_ptr<FileSystemComponent>> children;
};

void doWorking() {
    // 创建文件
    auto file1 = std::make_shared<File>("file1.txt");
    auto file2 = std::make_shared<File>("file2.txt");
    auto file3 = std::make_shared<File>("file3.txt");

    // 创建目录
    auto dir1 = std::make_shared<Directory>("dir1");
    auto dir2 = std::make_shared<Directory>("dir2");
    auto dir3 = std::make_shared<Directory>("dir3");

    // 组装文件系统
    dir1->add(file1);
    dir1->add(file2);

    dir2->add(file3);
    dir2->add(dir1);  // dir2 包含 dir1

    dir3->add(dir2);  // dir3 包含 dir2

    // 列出整个文件系统
    dir3->list();

    return ;
}

int main() {

	doWorking();
	return 0;
}

运行效果

四、总结

组合模式通过提供一个统一的接口来处理单个对象和对象组合,使得客户端能够以一致的方式操作树形结构中的元素,比如composite.cpp的代码设计中接口提供了统一的add()方法模拟目录和文件的包含关系,最后使用list()方法直观显示树形组合结构。组合模式特别适合处理具有部分-整体结构的系统,其中对象可以被递归地组合成树形结构。它使得客户端能够以一致的方式对待单个对象和对象组合,从而简化了代码和操作,提高了系统的灵活性和扩展性。

相关推荐
重生之我在20年代敲代码几秒前
strncpy函数的使用和模拟实现
c语言·开发语言·c++·经验分享·笔记
迷迭所归处6 小时前
C++ —— 关于vector
开发语言·c++·算法
CV工程师小林6 小时前
【算法】BFS 系列之边权为 1 的最短路问题
数据结构·c++·算法·leetcode·宽度优先
white__ice7 小时前
2024.9.19
c++
天玑y7 小时前
算法设计与分析(背包问题
c++·经验分享·笔记·学习·算法·leetcode·蓝桥杯
姜太公钓鲸2337 小时前
c++ static(详解)
开发语言·c++
菜菜想进步7 小时前
内存管理(C++版)
c语言·开发语言·c++
Joker100858 小时前
C++初阶学习——探索STL奥秘——模拟实现list类
c++
科研小白_d.s8 小时前
vscode配置c/c++环境
c语言·c++·vscode
湫兮之风8 小时前
c++:tinyxml2如何存储二叉树
开发语言·数据结构·c++