模式简介
组合模式的关键是定义了一个抽象构件类,它既可以代表叶子,又可以代表容器,而客户端针对该抽象构件类进行编程,无须知道它到底表示的是叶子还是容器,可以对其进行统一处理。
同时容器对象与抽象构件类之间还建立一个聚合关联关系,在容器对象中既可以包含叶子,也可以包含容器,以此实现递归组合,形成一个树形结构。
模式实现
一般借助于基类的指针容器进行实现,遍历地时候可以递归执行。具体参考下面的文件系统的例子。
UML类图
代码实例
有一个文件系统,系统中可以有文件和文件夹两种形式。文件或者文件夹只能由上一层的父节点删除。必须有一个FolderRoot作为根文件。文件夹可以删除或者添加文件,而文件没有这些操作。
#include <iostream>
#include <memory>
#include <cassert>
#include <string>
#include <vector>
#include <algorithm>
class Component {
public:
virtual void print(int n = 0) = 0; // 组件输出内容
// 添加新的组件
virtual void add(std::shared_ptr<Component> cpt) {
assert(false);
}
// 删除自身
virtual void remove(std::shared_ptr<Component> cpt) {
assert(false);
}
void setName(std::string name) {
m_strName = std::move(name);
}
protected:
std::string m_strName;
};
// 文件夹,无法执行添加子组件和删除子组件的操作
class File : public Component {
public:
File(std::string name = "") {
m_strName = std::move(name);
}
void print(int n = 0) override {
std::cout << "File: " << m_strName << std::endl;
}
};
// 可以删除或者添加文件,注意递归遍历的方式
class Folder : public Component {
public:
Folder(std::string name = "") {
m_strName = std::move(name);
}
void print(int n = 0) override {
std::string space;
for (int i = 0; i <= n; ++i) {
space += "---";
}
std::cout << "Folder: " << m_strName << "\n";
for (const auto& comp: m_vecChildren) {
std::cout << "|";
std::cout << space;
comp->print(n + 1);
}
}
void add(std::shared_ptr<Component> ptr) override{
m_vecChildren.emplace_back(std::move(ptr));
}
void remove(std::shared_ptr<Component> ptr) override {
auto& vec = m_vecChildren;
vec.erase(std::remove(vec.begin(), vec.end(), ptr), vec.end());
}
private:
std::vector<std::shared_ptr<Component>> m_vecChildren;
};
int main() {
auto f1 = std::make_shared<File>("1.txt");
auto f2 = std::make_shared<File>("2.pdf");
auto f3 = std::make_shared<File>("3.wav");
auto f4 = std::make_shared<File>("4.jpg");
auto f5 = std::make_shared<File>("5.png");
auto FA = std::make_shared<Folder>("A");
auto FB = std::make_shared<Folder>("B");
auto FC = std::make_shared<Folder>("C");
FA->add(f1);
FA->add(FB);
FB->add(f2);
FB->add(f3);
FC->add(f4);
FC->add(f5);
auto F0 = std::make_shared<Folder>("root");
F0->add(FA);
F0->add(FB);
F0->add(FC);
F0->print();
std::cout << "=============delete File5==============\n";
FC->remove(f5);
F0->print();
std::cout << "=============delete FolderA==============\n";
F0->remove(FA);
F0->print();
return 0;
}
输出:
Folder: root
|---Folder: A
|------File: 1.txt
|------Folder: B
|---------File: 2.pdf
|---------File: 3.wav
|---Folder: B
|------File: 2.pdf
|------File: 3.wav
|---Folder: C
|------File: 4.jpg
|------File: 5.png
=============delete File5==============
Folder: root
|---Folder: A
|------File: 1.txt
|------Folder: B
|---------File: 2.pdf
|---------File: 3.wav
|---Folder: B
|------File: 2.pdf
|------File: 3.wav
|---Folder: C
|------File: 4.jpg
=============delete FolderA==============
Folder: root
|---Folder: B
|------File: 2.pdf
|------File: 3.wav
|---Folder: C
|------File: 4.jpg