组合模式通过统一接口处理树形结构中的单个对象和组合对象,核心由Component、Leaf和Composite三部分构成,其中Component定义操作接口,Leaf实现叶子节点行为,Composite维护子节点列表并实现递归遍历,示例中使用智能指针管理文件系统中的目录与文件,确保资源安全且支持统一调用display方法展示层级结构。
在C++中,组合模式(Composite Pattern)非常适合用来实现树形结构,比如文件系统、菜单层级或组织架构。它允许你将对象组合成树形结构以表示“部分-整体”的层次关系,并且使得客户端可以统一处理单个对象和组合对象。
组合模式的核心角色
组合模式通常包含三个关键组成部分:
Component(组件)
:抽象基类,定义操作接口,如添加、删除子节点,获取子节点,执行操作等。
Leaf(叶子)
:最底层的节点,没有子节点,实现Component接口但不包含子节点管理逻辑。
Composite(容器)
:内部维护子节点列表,实现添加、删除、遍历等操作,可包含Leaf或其他Composite。
代码实现示例
下面是一个简单的树形结构实现,模拟文件系统中的文件和目录:
使用方式
构建一个简单的目录树并展示结构:
立即学习
“
C++免费学习笔记(深入)
”;
C知道
CSDN推出的一款AI技术问答工具
下载
输出结果会是类似这样的树形结构:
关键设计要点
使用组合模式时需要注意以下几点:
Component 提供统一接口,让客户端无需区分叶子和容器。
使用智能指针(如 unique_ptr)管理生命周期,避免内存泄漏。
容器类负责管理子节点的增删和遍历,叶子类只关注自身行为。
递归调用 display 或其他操作是组合模式的典型特征。
基本上就这些。组合模式通过统一接口和递归结构,让树形数据的构建和操作变得清晰自然。不复杂但容易忽略的是对所有权的管理,C++中推荐用智能指针来简化资源控制。
#include
#include
#include
#include
// 抽象组件类
class FileSystemComponent {
public:
virtual ~FileSystemComponent() = default;
virtual void display(int depth = 0) const = 0;
};
// 叶子类:文件
class File : public FileSystemComponent {
std::string name;
public:
explicit File(const std::string& fileName) : name(fileName) {}
void display(int depth) const override {
std::cout << std::string(depth, ' ') << "? " << name << "\n";
}
};
// 容器类:目录
class Directory : public FileSystemComponent {
std::string name;
std::vector> children;
public:
explicit Directory(const std::string& dirName) : name(dirName) {}
void add(std::unique_ptr component) {
children.push_back(std::move(component));
}
void display(int depth = 0) const override {
std::cout << std::string(depth, ' ') << "? " << name << "\n";
for (const auto& child : children) {
child->display(depth + 2);
}
}
};
int main() {
// 创建根目录
auto root = std::make_unique("Root");
// 添加文件到根目录
root->add(std::make_unique("main.cpp"));
root->add(std::make_unique("Makefile"));
// 创建子目录
auto srcDir = std::make_unique("src");
srcDir->add(std::make_unique("utils.cpp"));
srcDir->add(std::make_unique("main.cpp"));
auto includeDir = std::make_unique("include");
includeDir->add(std::make_unique("utils.h"));
// 将子目录加入根目录
srcDir->add(std::move(includeDir));
root->add(std::move(srcDir));
// 显示整个结构
root->display();
return 0;
}
? Root
? main.cpp
? Makefile
? src
? utils.cpp
? main.cpp
? include
? utils.h
