C++ 组合模式详解

组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构 来表示"部分-整体"的层次结构,使得客户端可以统一处理单个对象和组合对象。

核心概念

设计原则

组合模式遵循以下设计原则:

  1. 单一职责原则:将对象的结构和使用分离

  2. 开闭原则:可以添加新类型的组件而不修改现有代码

  3. 透明性:对单个对象和组合对象提供一致的操作接口

主要优点

  1. 统一处理:客户端可以一致地处理单个对象和组合对象

  2. 简化客户端代码:客户端不需要知道处理的是单个对象还是组合

  3. 灵活的结构:可以轻松添加新的组件类型

  4. 递归组合:支持递归结构,便于表示复杂的层次关系

模式结构

主要组件

  1. Component(抽象组件)

    • 定义所有组件的通用接口

    • 声明访问和管理子组件的方法(可选)

  2. Leaf(叶子组件)

    • 表示组合中的叶子节点(没有子元素)

    • 实现组件接口的基本行为

  3. 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));
    }
    // ... 其他方法 ...
};

实际应用场景

  1. 文件系统:文件和目录的层次结构

  2. GUI组件:窗口包含面板,面板包含按钮等

  3. 组织结构:公司部门与员工的层次关系

  4. 图形编辑:图形组合与简单图形的统一处理

  5. 菜单系统:菜单项和子菜单的统一处理

相关推荐
tankeven12 分钟前
HJ138 在树上游玩
c++·算法
山上三树22 分钟前
Qt Widget介绍
开发语言·qt
minji...25 分钟前
Linux 库制作与原理(三)深入动静态链接原理
linux·运维·服务器·c++
weixin_387534221 小时前
Ownership - Rust Hardcore Head to Toe
开发语言·后端·算法·rust
Queenie_Charlie1 小时前
Manacher算法
c++·算法·manacher
闻缺陷则喜何志丹1 小时前
【树的直径 离散化】 P7807 魔力滋生|普及+
c++·算法·洛谷·离散化·树的直径
csdn_zhangchunfeng2 小时前
Qt之slots和Q_SLOTS的区别
开发语言·qt
计算机安禾2 小时前
【C语言程序设计】第35篇:文件的打开、关闭与读写操作
c语言·开发语言·c++·vscode·算法·visual studio code·visual studio
kishu_iOS&AI2 小时前
Python - 链表浅析
开发语言·python·链表
不想写代码的星星2 小时前
告别 C 风格枚举:为什么你应该使用 enum class
c++