组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
模式定义
组合模式通过将对象组合成树状结构来表示部分-整体的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
模式结构
-
Component(抽象构件): 定义叶子和容器构件的共同接口
-
Leaf(叶子构件): 表示叶节点对象,没有子节点
-
Composite(容器构件): 表示容器节点对象,存储子部件并实现与子部件相关的操作
-
Client(客户端): 通过Component接口操作组合结构中的对象
应用场景
-
需要表示对象的"部分-整体"层次结构时
-
希望用户忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时
-
处理树形结构数据时
-
当系统需要动态地在层次结构中添加新的构件时
优点
-
可以清楚地定义分层次的复杂对象
-
客户端可以一致地使用组合结构和单个对象
-
更容易在组合体内加入新的构件
-
简化了客户端代码,客户端可以一致地处理简单元素和复杂元素
缺点
-
设计较复杂,客户端需要花更多时间理清类之间的层次关系
-
很难限制组合中的构件类型
-
在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
C++实用示例
示例1:文件系统实现
cpp
#include <iostream>
#include <string>
#include <vector>
#include <memory>
// 抽象构件
class FileSystemComponent {
public:
virtual ~FileSystemComponent() = default;
virtual void display(int depth = 0) const = 0;
virtual void add(std::unique_ptr<FileSystemComponent> component) {
throw std::runtime_error("Cannot add to a leaf component");
}
};
// 叶子构件 - 文件
class File : public FileSystemComponent {
std::string name;
public:
explicit File(const std::string& name) : name(name) {}
void display(int depth = 0) const override {
std::cout << std::string(depth * 2, ' ') << "- " << name << std::endl;
}
};
// 容器构件 - 目录
class Directory : public FileSystemComponent {
std::string name;
std::vector<std::unique_ptr<FileSystemComponent>> children;
public:
explicit Directory(const std::string& name) : name(name) {}
void display(int depth = 0) const override {
std::cout << std::string(depth * 2, ' ') << "+ " << name << std::endl;
for (const auto& child : children) {
child->display(depth + 1);
}
}
void add(std::unique_ptr<FileSystemComponent> component) override {
children.push_back(std::move(component));
}
};
int main() {
auto root = std::make_unique<Directory>("Root");
auto documents = std::make_unique<Directory>("Documents");
documents->add(std::make_unique<File>("Resume.pdf"));
documents->add(std::make_unique<File>("CoverLetter.docx"));
auto pictures = std::make_unique<Directory>("Pictures");
pictures->add(std::make_unique<File>("Vacation.jpg"));
pictures->add(std::make_unique<File>("Family.png"));
auto downloads = std::make_unique<Directory>("Downloads");
downloads->add(std::make_unique<File>("Setup.exe"));
root->add(std::move(documents));
root->add(std::move(pictures));
root->add(std::make_unique<File>("README.txt"));
root->add(std::move(downloads));
root->display();
}
示例2:图形绘制系统
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <cmath>
// 抽象构件
class Graphic {
public:
virtual ~Graphic() = default;
virtual void move(int x, int y) = 0;
virtual void draw() const = 0;
};
// 叶子构件 - 点
class Dot : public Graphic {
int x, y;
public:
Dot(int x, int y) : x(x), y(y) {}
void move(int x, int y) override {
this->x += x;
this->y += y;
}
void draw() const override {
std::cout << "Drawing a dot at (" << x << ", " << y << ")\n";
}
};
// 叶子构件 - 圆
class Circle : public Graphic {
int x, y;
int radius;
public:
Circle(int x, int y, int radius) : x(x), y(y), radius(radius) {}
void move(int x, int y) override {
this->x += x;
this->y += y;
}
void draw() const override {
std::cout << "Drawing a circle at (" << x << ", " << y
<< ") with radius " << radius << "\n";
}
};
// 容器构件 - 组合图形
class CompoundGraphic : public Graphic {
std::vector<std::unique_ptr<Graphic>> children;
public:
void add(std::unique_ptr<Graphic> graphic) {
children.push_back(std::move(graphic));
}
void move(int x, int y) override {
for (const auto& child : children) {
child->move(x, y);
}
}
void draw() const override {
std::cout << "=== Drawing a compound graphic ===\n";
for (const auto& child : children) {
child->draw();
}
std::cout << "=== End of compound graphic ===\n";
}
};
int main() {
auto all = std::make_unique<CompoundGraphic>();
all->add(std::make_unique<Dot>(1, 2));
all->add(std::make_unique<Circle>(5, 3, 10));
auto group = std::make_unique<CompoundGraphic>();
group->add(std::make_unique<Circle>(10, 10, 5));
group->add(std::make_unique<Dot>(10, 10));
all->add(std::move(group));
all->add(std::make_unique<Dot>(20, 20));
std::cout << "Initial drawing:\n";
all->draw();
all->move(5, 5);
std::cout << "\nAfter moving (5,5):\n";
all->draw();
}
示例3:组织架构系统
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <string>
// 抽象构件
class OrganizationUnit {
public:
virtual ~OrganizationUnit() = default;
virtual void display(int depth = 0) const = 0;
virtual void add(std::unique_ptr<OrganizationUnit> unit) {
throw std::runtime_error("Cannot add to a leaf unit");
}
virtual double getSalary() const = 0;
};
// 叶子构件 - 员工
class Employee : public OrganizationUnit {
std::string name;
double salary;
public:
Employee(const std::string& name, double salary) : name(name), salary(salary) {}
void display(int depth = 0) const override {
std::cout << std::string(depth * 2, ' ') << name
<< " (Salary: $" << salary << ")\n";
}
double getSalary() const override { return salary; }
};
// 容器构件 - 部门
class Department : public OrganizationUnit {
std::string name;
std::vector<std::unique_ptr<OrganizationUnit>> units;
public:
explicit Department(const std::string& name) : name(name) {}
void display(int depth = 0) const override {
std::cout << std::string(depth * 2, ' ') << "Department: " << name
<< " (Total Salary: $" << getSalary() << ")\n";
for (const auto& unit : units) {
unit->display(depth + 1);
}
}
void add(std::unique_ptr<OrganizationUnit> unit) override {
units.push_back(std::move(unit));
}
double getSalary() const override {
double total = 0.0;
for (const auto& unit : units) {
total += unit->getSalary();
}
return total;
}
};
int main() {
auto company = std::make_unique<Department>("ACME Corporation");
auto engineering = std::make_unique<Department>("Engineering");
engineering->add(std::make_unique<Employee>("John Doe", 85000));
engineering->add(std::make_unique<Employee>("Jane Smith", 95000));
auto qa = std::make_unique<Department>("Quality Assurance");
qa->add(std::make_unique<Employee>("Bob Johnson", 75000));
qa->add(std::make_unique<Employee>("Alice Williams", 80000));
engineering->add(std::move(qa));
company->add(std::move(engineering));
auto marketing = std::make_unique<Department>("Marketing");
marketing->add(std::make_unique<Employee>("Mike Brown", 90000));
marketing->add(std::make_unique<Employee>("Sarah Davis", 88000));
company->add(std::move(marketing));
company->add(std::make_unique<Employee>("CEO", 250000));
std::cout << "Company Structure:\n";
company->display();
std::cout << "\nTotal company salary: $" << company->getSalary() << std::endl;
}
示例4:UI组件系统
cpp
#include <iostream>
#include <vector>
#include <memory>
#include <string>
// 抽象构件
class UIComponent {
public:
virtual ~UIComponent() = default;
virtual void render() const = 0;
virtual void add(std::unique_ptr<UIComponent> component) {
throw std::runtime_error("Cannot add to a leaf component");
}
};
// 叶子构件 - 按钮
class Button : public UIComponent {
std::string label;
public:
explicit Button(const std::string& label) : label(label) {}
void render() const override {
std::cout << "[Button: " << label << "]\n";
}
};
// 叶子构件 - 文本框
class TextBox : public UIComponent {
std::string placeholder;
public:
explicit TextBox(const std::string& placeholder) : placeholder(placeholder) {}
void render() const override {
std::cout << "[TextBox: " << placeholder << "]\n";
}
};
// 容器构件 - 面板
class Panel : public UIComponent {
std::string title;
std::vector<std::unique_ptr<UIComponent>> children;
public:
explicit Panel(const std::string& title) : title(title) {}
void render() const override {
std::cout << "=== Panel: " << title << " ===\n";
for (const auto& child : children) {
child->render();
}
std::cout << "=== End of Panel ===\n";
}
void add(std::unique_ptr<UIComponent> component) override {
children.push_back(std::move(component));
}
};
// 容器构件 - 窗口
class Window : public UIComponent {
std::string title;
std::vector<std::unique_ptr<UIComponent>> children;
public:
explicit Window(const std::string& title) : title(title) {}
void render() const override {
std::cout << "**** Window: " << title << " ****\n";
for (const auto& child : children) {
child->render();
}
std::cout << "**** End of Window ****\n";
}
void add(std::unique_ptr<UIComponent> component) override {
children.push_back(std::move(component));
}
};
int main() {
auto loginWindow = std::make_unique<Window>("Login");
auto formPanel = std::make_unique<Panel>("Login Form");
formPanel->add(std::make_unique<TextBox>("Username"));
formPanel->add(std::make_unique<TextBox>("Password"));
auto buttonPanel = std::make_unique<Panel>("Actions");
buttonPanel->add(std::make_unique<Button>("Login"));
buttonPanel->add(std::make_unique<Button>("Cancel"));
loginWindow->add(std::move(formPanel));
loginWindow->add(std::move(buttonPanel));
std::cout << "Rendering UI:\n";
loginWindow->render();
}
这些示例展示了组合模式如何通过树形结构来表示部分-整体层次结构,使得客户端可以一致地处理单个对象和组合对象。组合模式特别适合用于构建递归结构,如文件系统、UI组件、组织结构等场景。