组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表示"部分-整体"的层次结构。组合模式使得客户端对单个对象和组合对象的使用具有一致性,也就是说,组合对象和单个对象对客户端来说是透明的,客户端无需关心它们是一个单独的对象还是一个包含子对象的组合对象。
组合模式的主要角色:
- 组件(Component):组件是组合模式中所有对象的基类,它为所有派生类提供一个公共接口。通常包含一些操作子节点的方法,比如添加、移除等。
- 叶子(Leaf):叶子节点表示树形结构中的叶子对象。叶子没有子节点,它实现了组件接口中的操作,但通常不支持子节点的相关操作。
- 组合(Composite):组合节点表示有子节点的复杂对象。它通常存储子节点,并定义了操作子节点的方法。
组合模式的结构:
class Component {
public:
virtual void Operation() = 0; // 定义接口操作
virtual void Add(Component* component) {}
virtual void Remove(Component* component) {}
virtual Component* GetChild(int index) { return nullptr; }
virtual ~Component() = default;
};
class Leaf : public Component {
public:
void Operation() override {
// 叶子节点的具体操作
std::cout << "Leaf Operation" << std::endl;
}
};
class Composite : public Component {
private:
std::vector<Component*> children;
public:
void Operation() override {
// 组合对象的具体操作,通常会递归调用子节点的操作
for (Component* child : children) {
child->Operation();
}
}
void Add(Component* component) override {
children.push_back(component);
}
void Remove(Component* component) override {
children.erase(std::remove(children.begin(), children.end(), component), children.end());
}
Component* GetChild(int index) override {
if (index >= 0 && index < children.size()) {
return children[index];
}
return nullptr;
}
};
使用组合模式的场景:
- 表示对象的部分-整体层次结构:当你想表示一个对象的部分-整体层次结构时,可以使用组合模式。
- 希望用户忽略组合对象与单个对象的不同:用户将统一地使用组合结构中的所有对象,而无需关心它们是单个对象还是组合对象。
示例代码
下面是一个使用组合模式的小例子,假设你要表示一个文件系统结构:
#include <iostream>
#include <vector>
#include <algorithm>
// 定义Component基类
class FileSystemComponent {
public:
virtual void Display() = 0;
virtual ~FileSystemComponent() = default;
};
// 定义叶子节点
class File : public FileSystemComponent {
private:
std::string name;
public:
File(const std::string& name) : name(name) {}
void Display() override {
std::cout << "File: " << name << std::endl;
}
};
// 定义组合节点
class Directory : public FileSystemComponent {
private:
std::string name;
std::vector<FileSystemComponent*> children;
public:
Directory(const std::string& name) : name(name) {}
void Add(FileSystemComponent* component) {
children.push_back(component);
}
void Display() override {
std::cout << "Directory: " << name << std::endl;
for (auto& child : children) {
child->Display();
}
}
~Directory() {
for (auto& child : children) {
delete child;
}
}
};
int main() {
Directory* root = new Directory("root");
root->Add(new File("file1.txt"));
root->Add(new File("file2.txt"));
Directory* subDir = new Directory("subdir");
subDir->Add(new File("file3.txt"));
root->Add(subDir);
root->Display();
delete root;
return 0;
}
在这个示例中,我们定义了一个简单的文件系统,其中包含文件(叶子节点)和目录(组合节点)。Directory
对象可以包含多个文件或子目录,通过组合模式,我们可以递归地显示整个文件系统的结构。
这个模式在需要处理树形结构并且希望客户代码能统一处理单个对象和组合对象时非常有用。