C++设计模式之组合模式

C++设计模式之组合模式攻略

简介

组合模式(Composite Pattern)是一种结构型设计模式。组合模式可以将对象组合成树形结构,表示“部分-整体”的结构层次关系,让客户端统一对待单个对象和组合对象。

结构

组合模式将对象组织成树形结构,有以下三个角色:

Component(抽象构件)

抽象构件定义了叶子和容器构件的公共接口,并可以提供一些默认的行为或属性。

class Component {
public:
    virtual ~Component() {}
    virtual void operation() = 0;
};

Leaf(叶子构件)

叶子构件是组成对象的最基本单元,其没有子节点,实现了抽象构件中的操作。

class Leaf : public Component {
public:
    virtual void operation() {
        // 叶子构件的操作
    }
};

Composite(容器构件)

容器构件包含一组子节点,其中部分或所有子节点是另一个容器构件,其实现了抽象构件中的操作,并且可以在内部管理子节点。

class Composite : public Component {
private:
    vector<Component*> components;
public:
    virtual void operation() {
        for (auto c : components) {
            c->operation();
        }
    }
    void addComponent(Component* c) {
        components.push_back(c);
    }
    void removeComponent(Component* c) {
        // 移除指定子节点
    }
};

示例1:菜单栏

假设我们正在开发一个图形界面程序,需要实现一个具备子菜单的菜单栏。用组合模式可以轻松实现该功能。

int main() {
    Composite* menuBar = new Composite;  // 菜单栏
    Composite* fileMenu = new Composite;  // 文件菜单
    Composite* editMenu = new Composite;  // 编辑菜单
    Leaf* openItem = new Leaf;  // 打开文件项
    Leaf* saveItem = new Leaf;  // 存储文件项
    Leaf* copyItem = new Leaf;  // 复制项
    Leaf* pasteItem = new Leaf;  // 粘贴项
    fileMenu->addComponent(openItem);
    fileMenu->addComponent(saveItem);
    editMenu->addComponent(copyItem);
    editMenu->addComponent(pasteItem);
    menuBar->addComponent(fileMenu);
    menuBar->addComponent(editMenu);
    menuBar->operation(); // 显示菜单栏及其子菜单
    return 0;
}

示例2:文件系统

下面是一个文件系统的例子。文件系统由一个根目录和多个文件和子目录组成。

class FileSystemNode {
public:
    virtual ~FileSystemNode() {}
    virtual int getNumOfFiles() = 0;
    virtual int getSize() = 0;
    virtual string getName() = 0;
    virtual void addNode(FileSystemNode* node) = 0;
    virtual void removeNode(FileSystemNode* node) = 0;
};

class File : public FileSystemNode {
public:
    File(const string& name, int size) : name_(name), size_(size) {}
    virtual int getNumOfFiles() { return 1; }
    virtual int getSize() { return size_; }
    virtual string getName() { return name_; }
    virtual void addNode(FileSystemNode* node) {}
    virtual void removeNode(FileSystemNode* node) {}
private:
    string name_;
    int size_;
};

class Directory : public FileSystemNode {
public:
    Directory(const string& name) : name_(name), size_(0) {}
    virtual ~Directory() {
        for (auto n : nodes_) {
            delete n;
        }
    }
    virtual int getNumOfFiles() {
        int count = 0;
        for (auto n : nodes_) {
            count += n->getNumOfFiles();
        }
        return count;
    }
    virtual int getSize() { return size_; }
    virtual string getName() { return name_; }
    virtual void addNode(FileSystemNode* node) {
        nodes_.push_back(node);
        size_ += node->getSize();
    }
    virtual void removeNode(FileSystemNode* node) {
        auto it = find(nodes_.begin(), nodes_.end(), node);
        if (it != nodes_.end()) {
            nodes_.erase(it);
            size_ -= node->getSize();
        }
    }
private:
    string name_;
    int size_;
    vector<FileSystemNode*> nodes_;
};

int main() {
    Directory* root = new Directory("R:");
    Directory* cDrive = new Directory("C:");
    Directory* dDrive = new Directory("D:");
    File* msPaint = new File("mspaint.exe", 112);
    File* myFile = new File("myFile.txt", 10);
    Directory* music = new Directory("Music");
    root->addNode(cDrive);
    root->addNode(dDrive);
    cDrive->addNode(msPaint);
    cDrive->addNode(myFile);
    dDrive->addNode(music);
    music->addNode(new File("song1.mp3", 8));
    music->addNode(new File("song2.mp3", 9));
    music->addNode(new Directory("Pop"));
    music->addNode(new Directory("Rock"));
    cout << "Num of files: " << root->getNumOfFiles() << endl;
    cout << "Total size: " << root->getSize() << endl;
    return 0;
}

本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++设计模式之组合模式 - Python技术站

(0)
上一篇 2023年5月22日
下一篇 2023年5月22日

相关文章

  • 详解c++ atomic原子编程中的Memory Order

    当使用C++中的原子类型进行编程时,需要指定原子操作的内存顺序(Memory Order),以保证多线程下的正确性和一致性。 C++中原子操作的内存顺序一共有4种: memory_order_relaxed:最轻松的内存顺序,不会保证原子操作的顺序,也不保证操作的内存可见性。当我们要进行仅仅是读写共享内存而无需考虑同步问题的操作时,可以使用memory_or…

    C 2023年5月23日
    00
  • set_new_handler(0)有什么用

    set_new_handler是C++语言提供的一个函数,用于设置一个新的内存分配失败处理程序。当内存分配操作失败时,该处理程序将被调用。当我们在C++程序中使用new操作符申请内存时,如果系统找不到合适的内存块,就会触发内存分配失败,进而导致程序抛出std::bad_alloc异常。 set_new_handler(0)的作用是设置一个新的内存分配失败处理…

    C 2023年5月23日
    00
  • JavaScript解构赋值详解

    JavaScript解构赋值详解 JavaScript解构赋值是一种简洁、快速、易读的语法,允许您从数组或对象中提取值并将它们赋值给变量。在本篇文章中,我们将详细探讨解构赋值的语法、使用方法和技巧。 什么是解构赋值? 解构赋值是ES6中的一种语法,它允许我们从数组、对象或函数参数中提取值,并将这些值赋给独立的变量。 对象解构 我们可以使用对象字面量来定义一个…

    C 2023年5月23日
    00
  • 基于C++的拼多多算法在线笔试题示例

    下面我将从以下几个方面详细讲解“基于C++的拼多多算法在线笔试题示例”的完整攻略: 题目描述和分析 解法思路 代码实现 示例说明 1. 题目描述和分析 这道题目要求实现一个函数,输入为一个整数n,输出为一个n*n的矩阵,其中矩阵中的元素按照从外向内的螺旋顺序填充。 例如,当n=3时,输出的矩阵应该为: [ [1, 2, 3], [8, 9, 4], [7, …

    C 2023年5月22日
    00
  • 深入解析C语言中的内存分配相关问题

    深入解析C语言中的内存分配相关问题 概述 在C语言中,内存分配是至关重要的。这是因为在C语言中,程序员需要手动地分配和释放内存以存储数据。C语言提供了几种内存分配方式,包括数据段、栈和堆。使用不当的内存分配方法可能导致程序运行时出现各种严重的问题,例如内存泄漏和段错误。本攻略将重点介绍C语言中的内存分配方式,并提供一些示例以帮助您更好地理解内存分配的概念。 …

    C 2023年5月23日
    00
  • C语言中%d和%i格式说明符的区别

    下面是详细讲解“C语言中%d和%i格式说明符的区别”的完整使用攻略。 在C语言中,%d和%i两个格式说明符都是用来输出整数类型的变量的,但是它们有一些细微的区别。 区别一:进制数的输出 %d格式说明符会将输出的整数按照10进制输出,而%i格式说明符则会根据整数变量的前缀来输出对应的进制数。 举个例子,假设有一个十六进制的整数变量x,值为0x1F,使用%d和%…

    C 2023年5月10日
    00
  • C语言实现简单的贪吃蛇游戏

    C语言实现简单的贪吃蛇游戏 概述 贪吃蛇是一款非常经典的游戏,很多初学者希望用C语言来实现这个小游戏,来体验C语言的基本语法和编程思路。本文将详细讲解如何使用C语言实现简单的贪吃蛇游戏。 游戏规则 游戏中,玩家操作一只“蛇”来吃食物,当蛇头碰到蛇身或者墙壁时游戏结束。游戏中蛇的长度会随着吃掉的食物而增加,而玩家需要使蛇尽可能地长,同时避免碰到自己的身体或者墙…

    C 2023年5月23日
    00
  • C语言用指针支持树

    关于“C语言用指针支持树”的完整使用攻略,我准备分为以下几个部分进行讲解: 树的定义与基本操作 使用指针实现树节点 树的遍历算法 示例程序 树的定义与基本操作 树是一种非常常见的数据结构,其结构非常清晰,由若干个节点组成,每个节点之间有唯一的父子关系。 一些常见的树操作包括: 插入节点:在树中插入一个新节点,将其作为指定节点的子节点。 删除节点:从树中删除给…

    C 2023年5月9日
    00
合作推广
合作推广
分享本页
返回顶部