c++实现组合模式完整源代码(附带源码)
c++实现组合模式完整源代码(附带源码)
一、项目背景详细介绍
在实际软件系统中,我们经常需要处理树形结构的数据,例如:
-
文件系统(文件 / 文件夹)
-
组织架构(公司 / 部门 / 员工)
-
UI 组件树(窗口 / 面板 / 控件)
-
菜单系统(菜单 / 子菜单 / 菜单项)
这些场景具有共同特点:
-
整体与部分具有一致的行为接口
-
客户端希望以统一方式处理单个对象和组合对象
-
对象之间天然形成树状层级关系
如果不使用设计模式,通常会:
-
对叶子对象和容器对象写大量 if/else 判断
-
客户端代码复杂、难以维护
-
难以扩展新的节点类型
组合模式(Composite Pattern) 正是为了解决这类问题而提出的。
组合模式属于 结构型设计模式,其核心思想是:
将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
本项目将使用 C++ 实现一个标准、教学友好的组合模式完整示例,通过“文件系统目录结构”来演示组合模式的典型用法。
二、项目需求详细介绍
项目功能需求如下:
-
使用组合模式表示文件与目录结构
-
文件和目录具有统一的抽象接口
-
目录可以包含子节点(文件或目录)
-
客户端以统一方式遍历和操作节点
-
代码结构清晰,适合教学与博客发布
非功能性需求:
-
符合组合模式标准结构
-
易于扩展新的节点类型
-
逻辑清晰、层次分明
三、相关技术详细介绍
3.1 组合模式核心角色
组合模式通常包含以下角色:
1. Component(抽象组件)
-
定义统一接口
-
声明公共行为(如显示、统计大小等)
2. Leaf(叶子节点)
-
表示树结构中的最小单元
-
不包含子节点
3. Composite(组合节点)
-
可以包含子节点
-
实现对子节点的管理行为
3.2 C++ 技术点
-
抽象基类与多态
-
STL 容器(
std::vector) -
智能指针(
std::shared_ptr)
四、实现思路详细介绍
整体实现思路如下:
-
定义抽象组件
FileSystemNode -
定义叶子节点
File -
定义组合节点
Directory -
目录节点内部维护子节点集合
-
客户端统一通过抽象接口操作对象
五、完整实现代码
说明:所有代码放在一个代码块中,不同文件使用注释区分
/************************************************
* 文件:Component.h
************************************************/
#include <iostream>
#include <vector>
#include <memory>
#include <string>
// 抽象组件
class FileSystemNode {
public:
virtual ~FileSystemNode() {}
virtual void display(int depth) = 0;
};
/************************************************
* 文件:Leaf.h
************************************************/
class File : public FileSystemNode {
private:
std::string name;
public:
explicit File(const std::string& name) : name(name) {}
void display(int depth) override {
for (int i = 0; i < depth; ++i) std::cout << "-";
std::cout << "File: " << name << std::endl;
}
};
/************************************************
* 文件:Composite.h
************************************************/
class Directory : public FileSystemNode {
private:
std::string name;
std::vector<std::shared_ptr<FileSystemNode>> children;
public:
explicit Directory(const std::string& name) : name(name) {}
void add(const std::shared_ptr<FileSystemNode>& node) {
children.push_back(node);
}
void display(int depth) override {
for (int i = 0; i < depth; ++i) std::cout << "-";
std::cout << "Directory: " << name << std::endl;
for (const auto& child : children) {
child->display(depth + 2);
}
}
};
/************************************************
* 文件:main.cpp
************************************************/
int main() {
auto root = std::make_shared<Directory>("root");
auto bin = std::make_shared<Directory>("bin");
auto usr = std::make_shared<Directory>("usr");
auto file1 = std::make_shared<File>("bash");
auto file2 = std::make_shared<File>("ls");
auto file3 = std::make_shared<File>("readme.txt");
bin->add(file1);
bin->add(file2);
usr->add(file3);
root->add(bin);
root->add(usr);
root->display(0);
return 0;
}
六、代码详细解读(仅解读方法作用)
6.1 FileSystemNode::display
定义统一的展示接口,使文件和目录可以被一致处理。
6.2 File::display
作为叶子节点,负责展示自身信息,不包含子节点逻辑。
6.3 Directory::add
向目录中添加子节点,实现树形结构的动态构建。
6.4 Directory::display
递归调用子节点的 display 方法,完成整个树结构的遍历展示。
七、项目详细总结
通过该示例,我们可以清晰看到组合模式的优势:
-
客户端无需区分叶子节点与组合节点
-
自然表达树形结构
-
符合开闭原则,易于扩展
缺点:
-
设计初期需要抽象能力
-
不适合对节点类型差异要求极高的场景
八、项目常见问题及解答
Q1:组合模式和装饰模式的区别?
A:组合模式关注结构层次,装饰模式关注功能增强。
Q2:组合模式是否一定是树结构?
A:通常是树结构,但也可以是有向无环图。
Q3:叶子节点需要实现 add 方法吗?
A:通常不需要,可在抽象层中留空或抛异常。
九、扩展方向与性能优化
-
增加 remove / getChild 等接口
-
结合迭代器模式进行遍历
-
为节点增加权限或统计功能
-
应用于 GUI 组件树
-
与访问者模式结合进行复杂操作
更多推荐
所有评论(0)