• 【C++设计模式之组合模式:结构型】分析及示例


    简介

    组合模式是一种结构型设计模式,它能够将对象组合成树形结构以表示“整体-部分”的层次结构,并且能够使用相同的方式处理单个对象和组合对象。组合模式使得客户端可以一致地处理单个对象和组合对象,无需关心具体的对象类型。

    组合模式将对象组织成树型结构,其中树的节点可以是单个对象或者组合对象。通过将对象以树形的方式组合,可以将单个对象和组合对象一视同仁。这种方式使得客户端无需区分单个对象和组合对象,可以递归地处理整个树结构,从而简化了客户端代码。

    描述

    组合模式涉及以下角色:

    1. 组件(Component):是组合模式中的树节点接口,声明了可以对子节点进行操作的方法,定义了组合对象和叶子对象的共有接口。
    2. 组合(Composite):是组合模式中的非叶子节点类,实现了组件接口,并保存了一个子节点的列表。组合对象可以包含其他组合对象或叶子对象。
    3. 叶子(Leaf):是组合模式中的叶子节点类,实现了组件接口,表示组合对象中的单个对象。

    原理

    组合模式的原理是将组合对象和叶子对象统一处理,客户端无需区分对待。组合对象中可以包含其他组合对象或叶子对象,这种递归结构可以无限扩展。

    类图

    在这里插入图片描述

    1、Component:组合模式中的“根节点”,可以是接口、抽象类、普通类,该类中定义了其子类的所有共性内容,并且该类中还存在着用于访问和管理它子部件的方法。
    2、Leaf:组合中的叶子节点,也就是最末端的节点,该节点下不会再有子节点。
    3、Composite:非叶子节点,它的作用是存储子部件,并且在Composite中实现了对子部件的相关操作。

    示例

    假设有一个文件系统,在文件系统中,有文件夹(组合对象)和文件(叶子对象)。文件夹可以包含其他文件夹或文件,而文件本身不能包含其他对象。可以使用组合模式来处理文件系统中的对象。

    在示例中,有三个主要类:

    1. Component(组件):表示组合模式中的树节点,定义了可以对子节点进行操作(如添加、删除、打印等)的接口。
    2. Composite(组合):表示组合模式中的非叶子节点,实现了组件接口,并保存了一个子节点的列表。
    3. Leaf(叶子):表示组合模式中的叶子节点,实现了组件接口,表示组合对象中的单个对象。

    C++示例代码:

    #include
    #include
    #include
    
    using namespace std;
    
    // 组件接口
    class Component {
    public:
        virtual void add(Component* component) = 0;
        virtual void remove(Component* component) = 0;
        virtual void print() = 0;
    };
    
    // 组合类
    class Composite : public Component {
    private:
        string name;
        vector<Component*> children;
    
    public:
        Composite(const string& name) : name(name) {}
    
        void add(Component* component) override {
            children.push_back(component);
        }
    
        void remove(Component* component) override {
            for (auto it = children.begin(); it != children.end(); ++it) {
                if (*it == component) {
                    children.erase(it);
                    break;
                }
            }
        }
    
        void print() override {
            cout << "Folder: " << name << endl;
            for (auto child : children) {
                child->print();
            }
        }
    };
    
    // 叶子类
    class Leaf : public Component {
    private:
        string name;
    
    public:
        Leaf(const string& name) : name(name) {}
    
        void add(Component* component) override {
            cout << "Cannot add to a leaf." << endl;
        }
    
        void remove(Component* component) override {
            cout << "Cannot remove from a leaf." << endl;
        }
    
        void print() override {
            cout << "File: " << name << endl;
        }
    };
    
    int main() {
        Component* root = new Composite("root");
        Component* folder1 = new Composite("folder1");
        Component* folder2 = new Composite("folder2");
    
        Component* file1 = new Leaf("file1");
        Component* file2 = new Leaf("file2");
        Component* file3 = new Leaf("file3");
    
        root->add(folder1);
        root->add(folder2);
    
        folder1->add(file1);
        folder1->add(file2);
    
        folder2->add(file3);
    
        root->print();
    
        delete root;
        delete folder1;
        delete folder2;
        delete file1;
        delete file2;
        delete file3;
    
        return 0;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93

    输出结果

    Folder: root
    Folder: folder1
    File: file1
    File: file2
    Folder: folder2
    File: file3
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    解释

    在示例中,使用组合模式创建了一个文件系统的树形结构。树的根节点是一个组合对象,包含了两个子节点(文件夹)。每个文件夹又包含了一些子节点(文件或其他文件夹)。通过使用组合模式,可以统一处理所有的节点,无论是文件夹还是文件,都可以使用相同的方式进行操作。

    结论

    组合模式提供了一种处理整体-部分结构的方式,使得客户端代码可以统一处理单个对象和组合对象。通过使用组合模式,可以实现树形结构的组织和操作,从而更好地管理复杂的对象结构。

    应用场景

    • 处理树形结构的场景,例如文件系统、组织结构等。
    • 需要统一处理单个对象和组合对象的场景,例如图形界面中的组件布局、菜单系统等。
    • 需要递归地处理对象的场景,例如目录结构的遍历、文件搜索等。
    • 需要实现树形操作的场景,例如代码抽象语法树的操作。

    总之,组合模式可以使得客户端无需区分单个对象和组合对象,可以统一地处理对象的层次结构。它提供了一种灵活且可扩展的方式来处理整体-部分结构,适用于需要处理层次结构的场景。

  • 相关阅读:
    Scikit-Learn快速生成分类数据集
    智联汽车 — 自动/辅助驾驶技术
    人脸活体检测技术的应用,有效避免人脸识别容易被攻击的缺陷
    Spring 全家桶 第六章:Spring MVC 实践
    免费域名证书最新申请方式大全
    Java爬虫详解
    ardupilot 关于设备车Rover的学习《2》------如何解锁
    一、爬虫基本概念
    【论文精读】分类扩散模型:重振密度比估计(Revitalizing Density Ratio Estimation)
    PaddlePaddle自然语言处理总结
  • 原文地址:https://blog.csdn.net/MrHHHHHH/article/details/133654867