当前位置: 首页 > article >正文

【C++设计模式】第八篇:组合模式(Composite)

注意:复现代码时,确保 VS2022 使用 C++17/20 标准以支持现代特性。

树形结构的统一操作接口


1. 模式定义与用途

核心思想

  • 组合模式:将对象组合成树形结构以表示“部分-整体”层次结构,使得客户端可以统一处理单个对象和组合对象。
  • 关键用途
    1.简化递归结构操作(如遍历目录树、渲染UI控件树)。
    2.隐藏复杂结构的差异,提供一致性接口。

​经典场景

  1. 文件系统管理(文件与文件夹的统一操作)。
  2. 图形界面容器(窗口包含按钮、面板等子控件)。

2. 模式结构解析

UML类图

+---------------------+  
|      Component      |  
+---------------------+  
| + add(c: Component) |  
| + remove(c: Component)|  
| + operation()       |  
+---------------------+  
          ^  
          |  
  +-------+-------+  
  |               |  
+-----------------+ +-----------------+  
|    Composite    | |      Leaf       |  
+-----------------+ +-----------------+  
| - children: list | | + operation()  |  
| + operation()    | +-----------------+  
+-----------------+  

角色说明

  1. Component:抽象接口,定义叶子和容器的共同操作(如add、remove)。
  2. Leaf:叶子节点,无子组件(如文件)。
  3. Composite:容器节点,存储子组件并实现递归逻辑(如文件夹)。

3. 简单示例:透明模式(统一接口)​

#include <iostream>  
#include <vector>  
#include <memory>  

// 抽象组件(透明模式:叶子与容器接口一致)  
class FileSystemComponent {  
public:  
    virtual ~FileSystemComponent() = default;  
    virtual void add(std::shared_ptr<FileSystemComponent> item) {  
        throw std::runtime_error("叶子节点不支持此操作");  
    }  
    virtual void list() const = 0;  
};  

// 叶子:文件  
class File : public FileSystemComponent {  
public:  
    File(const std::string& name) : name_(name) {}  

    void list() const override {  
        std::cout << "文件: " << name_ << "\n";  
    }  

private:  
    std::string name_;  
};  

// 容器:文件夹  
class Folder : public FileSystemComponent {  
public:  
    Folder(const std::string& name) : name_(name) {}  

    void add(std::shared_ptr<FileSystemComponent> item) override {  
        children_.push_back(item);  
    }  

    void list() const override {  
        std::cout << "文件夹: " << name_ << "\n";  
        for (const auto& child : children_) {  
            child->list();  
        }  
    }  

private:  
    std::string name_;  
    std::vector<std::shared_ptr<FileSystemComponent>> children_;  
};  

// 使用示例  
int main() {  
    auto root = std::make_shared<Folder>("根目录");  
    auto docs = std::make_shared<Folder>("文档");  
    auto file1 = std::make_shared<File>("简历.pdf");  
    auto file2 = std::make_shared<File>("笔记.txt");  

    docs->add(file1);  
    docs->add(file2);  
    root->add(docs);  

    root->list();  // 递归列出所有内容  
}  

4. 完整代码:安全模式与扩展功能

场景:图形界面控件树

#include <iostream>  
#include <vector>  
#include <memory>  
#include <algorithm>  

// 抽象组件(安全模式:叶子与容器接口分离)  
class UIComponent {  
public:  
    virtual ~UIComponent() = default;  
    virtual void render() const = 0;  
    virtual std::string getName() const = 0;  
};  

// 容器接口(仅容器支持添加/删除)  
class UIContainer : public UIComponent {  
public:  
    virtual void add(std::shared_ptr<UIComponent> child) = 0;  
    virtual void remove(std::shared_ptr<UIComponent> child) = 0;  
};  

// 叶子:按钮  
class Button : public UIComponent {  
public:  
    Button(const std::string& name) : name_(name) {}  

    void render() const override {  
        std::cout << "渲染按钮: " << name_ << "\n";  
    }  

    std::string getName() const override {  
        return name_;  
    }  

private:  
    std::string name_;  
};  

// 容器:面板  
class Panel : public UIContainer {  
public:  
    Panel(const std::string& name) : name_(name) {}  

    void add(std::shared_ptr<UIComponent> child) override {  
        children_.push_back(child);  
    }  

    void remove(std::shared_ptr<UIComponent> child) override {  
        auto it = std::find(children_.begin(), children_.end(), child);  
        if (it != children_.end()) {  
            children_.erase(it);  
        }  
    }  

    void render() const override {  
        std::cout << "渲染面板: " << name_ << "\n";  
        for (const auto& child : children_) {  
            child->render();  
        }  
    }  

    std::string getName() const override {  
        return name_;  
    }  

private:  
    std::string name_;  
    std::vector<std::shared_ptr<UIComponent>> children_;  
};  

// 客户端代码  
int main() {  
    auto mainPanel = std::make_shared<Panel>("主面板");  
    auto button1 = std::make_shared<Button>("确定");  
    auto button2 = std::make_shared<Button>("取消");  
    auto subPanel = std::make_shared<Panel>("子面板");  
    auto button3 = std::make_shared<Button>("更多");  

    subPanel->add(button3);  
    mainPanel->add(button1);  
    mainPanel->add(button2);  
    mainPanel->add(subPanel);  

    mainPanel->render();  
    // 输出:  
    // 渲染面板: 主面板  
    // 渲染按钮: 确定  
    // 渲染按钮: 取消  
    // 渲染面板: 子面板  
    // 渲染按钮: 更多  
}  

5. 优缺点分析

优点​​缺点
统一处理简单与复杂对象透明模式违反接口隔离原则(叶子支持add)
支持递归操作与树形遍历容器需管理子节点生命周期,增加复杂度
灵活扩展新组件类型对性能敏感场景不友好(深层次遍历)

6. 调试与优化策略

调试技巧(VS2022)​

  1. 递归调用跟踪
    在render()方法内设置条件断点(如getName() == “子面板”)。
  2. 内存泄漏检测
    使用VS2022内置诊断工具(Debug > Windows > Memory Usage)。

性能优化

  1. 缓存遍历结果
class CachedPanel : public Panel {  
public:  
    void render() const override {  
        if (!cached_) {  
            cachedOutput_ = generateRenderOutput();  
            cached_ = true;  
        }  
        std::cout << cachedOutput_;  
    }  
private:  
    mutable bool cached_ = false;  
    mutable std::string cachedOutput_;  
};  
  1. 并行化渲染
#include <execution>  
void Panel::render() const {  
    std::for_each(std::execution::par, children_.begin(), children_.end(),  
        [](const auto& child) { child->render(); });  
}  

http://www.kler.cn/a/576237.html

相关文章:

  • 深入探讨AI-Ops架构 第一讲 - 运维的进化历程以及未来发展趋势
  • redisinsight 默认端口改成5540了
  • OpenCV计算摄影学(17)两个图像之间执行无缝克隆操作函数 seamlessClone()
  • maven高级-05.私服
  • 【银河麒麟高级服务器操作系统实例】虚拟机桥接网络问题分析及处理
  • Linux驱动开发(1.基础创建)
  • ❌Manus?✅OpenManus + DeepSeek!!!
  • springboot项目使用中创InforSuiteAS替换tomcat
  • pandas-基础(数据结构及文件访问)
  • BP神经网络终极进化:2025量子增强版Python实现(附元宇宙金融实战)
  • 深度学习(斋藤康毅)学习笔记(六)反向传播3
  • C#实现应用程序单个运行,防止重复启动
  • 算法随打:拼写单词
  • oracle通过dmp导入数据
  • 【JAVA架构师成长之路】【Redis】第17集:Redis热点Key问题分析与解决方案
  • 【CSS】Tailwind CSS 与传统 CSS:设计理念与使用场景对比
  • .NET高级应用---自定义Ioc容器(附带源码)
  • Qt6.8.2创建WebAssmebly项目使用FFmpeg资源
  • 论文阅读《TrustRAG: An Information Assistant with Retrieval AugmentedGeneration》
  • K8S学习之基础十四:k8s中Deployment控制器概述