🔄 回顾 Day 13:桥接模式小结
在 Day 13 中,我们学习了桥接模式(Bridge Pattern):
- 用于将“抽象”与“实现”分离,适用于双维度变化场景(如图形类型 × 渲染方式)。
- 它强调组合替代继承,解决类爆炸问题,提升系统可扩展性。
今天我们进入一个构建层级结构的重要模式——组合模式(Composite Pattern)。
组合模式的目标是:让你以一致的方式对待单个对象和对象集合(树形结构)。
一、组合模式的核心动机
✅ 什么是组合模式?
组合模式用于构建树状结构的对象系统,例如:
- 文件夹包含文件和子文件夹
- UI 容器包含多个控件
- 公司组织结构:员工 ← 部门 ← 公司
核心哲学:
将对象组成树形结构,客户端可以“统一操作”叶子节点与中间节点。
二、UML 结构图
+----------------+
| Component |<------------------------------+
+----------------+ |
| +operation() | |
+----------------+ |/\ |/ \ |
+-------------------+ +---------------------+ |
| Leaf | | Composite | |
+-------------------+ +---------------------+ |
| +operation() | | +add(Component*) | || +remove(Component*) | || +operation() | |+---------------------+ |
三、角色说明
角色 | 职责说明 |
---|---|
Component | 抽象类,统一接口 |
Leaf | 叶子节点,实现具体功能,不含子节点 |
Composite | 组合节点,内部维护子组件列表 |
四、C++ 实现:文件系统结构
✅ 抽象组件接口
class FileSystemNode {
public:virtual void display(int depth = 0) = 0;virtual ~FileSystemNode() = default;
};
✅ 叶子节点:文件
class File : public FileSystemNode {std::string name_;
public:File(const std::string& name) : name_(name) {}void display(int depth = 0) override {std::cout << std::string(depth, '-') << name_ << std::endl;}
};
✅ 组合节点:文件夹
class Directory : public FileSystemNode {std::string name_;std::vector<std::unique_ptr<FileSystemNode>> children_;public:Directory(const std::string& name) : name_(name) {}void add(std::unique_ptr<FileSystemNode> node) {children_.emplace_back(std::move(node));}void display(int depth = 0) override {std::cout << std::string(depth, '-') << name_ << "/" << std::endl;for (const auto& child : children_) {child->display(depth + 2);}}
};
✅ 使用示例
int main() {auto root = std::make_unique<Directory>("root");root->add(std::make_unique<File>("file1.txt"));auto subDir = std::make_unique<Directory>("subdir");subDir->add(std::make_unique<File>("file2.txt"));subDir->add(std::make_unique<File>("file3.txt"));root->add(std::move(subDir));root->display();return 0;
}
输出:
root/
--file1.txt
--subdir/
----file2.txt
----file3.txt
五、组合模式适用场景
场景 | 对象树结构说明 |
---|---|
操作系统文件系统 | 文件 + 文件夹,操作接口统一 |
图形界面控件 | 窗口、容器、按钮、文本框构成控件树 |
公司组织架构 | CEO → 部门主管 → 员工 |
报表结构层级 | 表头、表体、表尾、字段 |
HTML DOM 树 | 节点 + 元素 + 属性 |
六、优点与缺点总结
✅ 优点:
- 统一接口,客户端无差别调用
- 树结构天然适合层次建模
- 扩展方便,添加新节点只需实现 Component
❗ 缺点:
- 违背接口隔离原则:叶子节点和组合节点共用接口,部分函数空实现
- 调试复杂,结构越深越难定位问题
七、与装饰器 / 责任链等模式对比
模式 | 核心区别 | 类似点 |
---|---|---|
Composite | 结构树形,有聚合子对象 | Component 接口统一 |
Decorator | 功能增强,包裹单一对象 | 接口一致、动态组合 |
Chain | 责任链传递,节点决定是否继续传递 | 多节点连接,共同参与处理 |
八、面试回答模板
“在我们的配置中心中,使用组合模式构建配置节点树,既可以是叶子属性(字段),也可以是组合节点(嵌套组)。所有节点都继承自统一接口,使我们可以用递归统一地遍历配置结构、序列化、验证,代码简洁且扩展性好。”
✅ 建议突出树形结构、递归遍历、统一调用等优势。
九、记忆口诀
“树形结构走统一,组合调用不分离;叶子整体皆一类,层层嵌套递归易。”
十、明日预告:Day 15
享元模式(Flyweight Pattern):通过共享技术减少对象数量,提升内存利用效率。