组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表示"部分-整体"的层次结构,使得客户端可以统一处理单个对象和组合对象。
核心概念
设计原则
组合模式遵循以下设计原则:
单一职责原则:将对象的结构和使用分离
开闭原则:可以添加新类型的组件而不修改现有代码
透明性:对单个对象和组合对象提供一致的操作接口
主要优点
统一处理:客户端可以一致地处理单个对象和组合对象
简化客户端代码:客户端不需要知道处理的是单个对象还是组合
灵活的结构:可以轻松添加新的组件类型
递归组合:支持递归结构,便于表示复杂的层次关系
模式结构
主要组件
Component(抽象组件)
定义所有组件的通用接口
声明访问和管理子组件的方法(可选)
Leaf(叶子组件)
表示组合中的叶子节点(没有子元素)
实现组件接口的基本行为
Composite(复合组件)
存储子组件(可以是Leaf或其他Composite)
实现与子组件相关的操作
完整代码示例
#include <iostream>
#include <vector>
#include <memory>
#include <string>
#include <algorithm>
// ==================== 抽象组件 ====================
class FileSystemComponent {
public:
virtual void display(int depth = 0) const = 0;
virtual void add(std::unique_ptr<FileSystemComponent> component) {
throw std::runtime_error("不支持添加操作");
}
virtual void remove(FileSystemComponent* component) {
throw std::runtime_error("不支持删除操作");
}
virtual ~FileSystemComponent() = default;
};
// ==================== 叶子组件 ====================
class File : public FileSystemComponent {
std::string name_;
int size_;
public:
File(const std::string& name, int size) : name_(name), size_(size) {}
void display(int depth = 0) const override {
std::cout << std::string(depth * 2, ' ')
<< "- " << name_ << " (" << size_ << " KB)" << 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));
}
void remove(FileSystemComponent* component) override {
auto it = std::remove_if(children_.begin(), children_.end(),
[component](const std::unique_ptr<FileSystemComponent>& ptr) {
return ptr.get() == component;
});
children_.erase(it, children_.end());
}
};
// ==================== 客户端代码 ====================
int main() {
std::cout << "=== 文件系统结构 ===" << std::endl;
// 创建根目录
auto root = std::make_unique<Directory>("根目录");
// 添加文件到根目录
root->add(std::make_unique<File>("readme.txt", 100));
root->add(std::make_unique<File>("program.exe", 1024));
// 创建子目录
auto documents = std::make_unique<Directory>("文档");
documents->add(std::make_unique<File>("report.doc", 250));
documents->add(std::make_unique<File>("presentation.ppt", 500));
// 在子目录中再创建子目录
auto images = std::make_unique<Directory>("图片");
images->add(std::make_unique<File>("photo1.jpg", 800));
images->add(std::make_unique<File>("photo2.jpg", 900));
documents->add(std::move(images));
// 将子目录添加到根目录
root->add(std::move(documents));
// 显示完整的文件系统结构
root->display();
return 0;
}
}
模式变体
1. 透明式组合模式
// 在抽象组件中声明所有方法(包括管理子组件的方法)
class Graphic {
public:
virtual void draw() const = 0;
virtual void add(std::unique_ptr<Graphic> graphic) {
throw std::runtime_error("不支持添加操作");
}
virtual void remove(Graphic* graphic) {
throw std::runtime_error("不支持删除操作");
}
virtual ~Graphic() = default;
};
2. 安全式组合模式
// 只在复合组件中声明管理子组件的方法
class Graphic {
public:
virtual void draw() const = 0;
virtual ~Graphic() = default;
};
class CompositeGraphic : public Graphic {
std::vector<std::unique_ptr<Graphic>> children_;
public:
void add(std::unique_ptr<Graphic> graphic) {
children_.push_back(std::move(graphic));
}
// ... 其他方法 ...
};
实际应用场景
文件系统:文件和目录的层次结构
GUI组件:窗口包含面板,面板包含按钮等
组织结构:公司部门与员工的层次关系
图形编辑:图形组合与简单图形的统一处理
菜单系统:菜单项和子菜单的统一处理