C++实现设计模式---组合模式 (Composite)
组合模式 (Composite)
组合模式 是一种结构型设计模式,它将对象组合成树形结构以表示“部分-整体”的层次结构。组合模式使客户端对单个对象和组合对象的使用具有一致性。
意图
- 将对象组合成树形结构,以表示“部分-整体”的层次结构。
- 使得客户端可以以一致的方式处理单个对象和对象的组合。
使用场景
-
需要表示部分与整体的层次结构:
- 如文件系统、组织架构等。
-
客户端需要以一致的方式处理单个对象和组合对象:
- 统一处理方式简化了客户端的代码逻辑。
参与者角色
-
组件 (Component)
- 定义了组合对象和叶子对象的公共接口。
-
叶子 (Leaf)
- 表示层次结构的叶子节点,没有子节点。
-
组合 (Composite)
- 表示层次结构中的非叶子节点,存储子节点,并实现与子节点相关的操作。
-
客户端 (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
方法。 - 提供了默认的
add
和remove
方法,叶子类中默认抛出异常。
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)
- 表示树结构的非叶子节点,例如目录。组合对象可以包含叶子节点和其他组合对象。
- 提供
add
和remove
方法,用于添加或移除子节点。
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(); // 显示文件系统结构
优缺点
优点
- 统一接口:
- 客户端可以以一致的方式处理单个对象和组合对象。
- 灵活性高:
- 可以很容易地扩展新类型的叶子节点或组合对象。
- 简化客户端代码:
- 客户端不需要了解对象的具体类型,简化了代码逻辑。
缺点
- 可能导致系统复杂性增加:
- 如果对象种类较多,系统会变得更加复杂。
- 对子节点的管理较难:
- 子节点的添加和删除操作可能需要额外的逻辑。
适用场景
-
需要表示部分与整体的层次结构:
- 如图形系统中的图形组件、文件系统中的目录和文件。
-
客户端需要统一对待单个对象和组合对象:
- 组合模式可以简化客户端的操作逻辑。
总结
组合模式通过将对象组合成树形结构,使得客户端能够统一地处理单个对象和组合对象,特别适用于表示部分-整体层次结构的场景。
原文地址:https://blog.csdn.net/Johnor/article/details/145232330
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!