• C++设计模式——Composite组合模式


    一,组合模式简介

    真实世界中,像企业组织、文档、图形软件界面等案例,它们在结构上都是分层次的。将系统分层次的方式使得统一管理和添加不同子模块变得容易,在软件开发中,组合模式的设计思想和它们类似。

    组合模式是一种结构型设计模式,该模式将对象组合成树状结构,以便于分层和统一管理。

    组合模式用于为复杂的分层的系统结构定义基本的蓝图,并对外提供统一的接口,简化了系统组件的使用方法。

    二,组合模式的结构

    1.组件类(Component):声明了统一的抽象接口。它定义了Leaf类和Composite类的通用函数接口。

    2.叶子节点类(Leaf):提供了Component类的接口实现,组合模式中的最小单元。

    3.组合类(Composite):也提供了Component类的接口实现,其中包含多个Component对象。它对子组件进行了封装,使用客户端(Client)可以像操作单个组件一样使用整个组合。

    对应UML类图:

    三,组合模式代码样例

    Demo1:先操作叶子节点,后操作主节点

    1. #include
    2. #include
    3. class Component {
    4. public:
    5. virtual void operation() const = 0;
    6. virtual ~Component() {}
    7. };
    8. class Leaf : public Component {
    9. public:
    10. Leaf(const std::string& name) : name_(name) {}
    11. virtual void operation() const override {
    12. std::cout << "Operation on leaf: " << name_ << std::endl;
    13. }
    14. private:
    15. std::string name_;
    16. };
    17. class Composite : public Component {
    18. public:
    19. Composite(const std::string& name) : name_(name), children_{} {}
    20. void add(Component* component) {
    21. children_.push_back(component);
    22. }
    23. void operation() const override {
    24. for (const auto& child : children_) {
    25. child->operation();
    26. }
    27. std::cout << "Operation on composite: " << name_ << std::endl;
    28. }
    29. private:
    30. std::vector children_;
    31. std::string name_;
    32. };
    33. int main() {
    34. Composite root("Composite Root");
    35. Leaf leaf1("Leaf 1");
    36. Leaf leaf2("Leaf 2");
    37. Leaf leaf3("Leaf 3");
    38. root.add(&leaf1);
    39. root.add(&leaf2);
    40. root.add(&leaf3);
    41. root.operation();
    42. return 0;
    43. }

    运行结果:

    1. Operation on leaf: Leaf 1
    2. Operation on leaf: Leaf 2
    3. Operation on leaf: Leaf 3
    4. Operation on composite: Composite Root

    Demo2:先操作主节点,后操作叶子节点

    1. #include
    2. #include
    3. class Component {
    4. public:
    5. virtual ~Component() {}
    6. virtual void operation() const = 0;
    7. };
    8. class Leaf : public Component {
    9. public:
    10. Leaf(const std::string& name) : name(name) {}
    11. virtual void operation() const override {
    12. std::cout << "Operation on leaf: " << name << '\n';
    13. }
    14. private:
    15. std::string name;
    16. };
    17. class Composite : public Component {
    18. public:
    19. Composite(const std::string& name) : Component(), children(), _name(name) {}
    20. void add(Component* component) {
    21. children.push_back(component);
    22. }
    23. void remove(Component* component) {
    24. children.erase(std::remove(children.begin(),
    25. children.end(),
    26. component),
    27. children.end());
    28. }
    29. void operation() const override {
    30. std::cout << "Operation on composite: " << _name << '\n';
    31. for (auto& child : children)
    32. child->operation();
    33. }
    34. private:
    35. std::vector children;
    36. std::string _name;
    37. };
    38. int main() {
    39. Composite root("Composite1");
    40. root.add(new Leaf("Leaf1"));
    41. root.add(new Leaf("Leaf2"));
    42. root.add(new Composite("Composite2"));
    43. root.add(new Leaf("Leaf3"));
    44. root.operation();
    45. return 0;
    46. }

    运行结果:

    1. Operation on composite: Composite1
    2. Operation on leaf: Leaf1
    3. Operation on leaf: Leaf2
    4. Operation on composite: Composite2
    5. Operation on leaf: Leaf3

    四,组合模式的应用场景

    平面设计软件开发:在Photoshop等应用程序中,形状、线条和文本等图形元素可以组合成复杂的设计。

    文件系统:使用组合模式来表示文件和目录,从而形成可以统一处理和查询的分层结构。

    UI框架开发:基于组合模式,可以让UI组件(如按钮、标签和面板等)组合成复杂的布局或界面。

    文档编辑器:使用组合模式来实现文档的段落和文本等层次结构。

    企业软件开发:企业软件通常对组织结构进行建模,包括部门、团队和员工。组合模式用于实现组织单位及其内部员工的层次结构。

    五,组合模式的优缺点

    组合模式的优点:

    1.便于维护和重构,修改单个组件的代码不会影响整个系统的功能。

    2.有树形结构的先天优势,可以很方便地统一添加、删除或修改子节点。

    3.通过拆分子组件,提高了模块间的独立性和可重用性。

    4.符合"单一职责原则",组合中的每个对象只关注自己的职责,不需要考虑整个组合中的功能配合。

    组合模式的缺点:

    1.性能开销大,该模式涉及了对象的动态创建和管理,频繁操作可能会引起性能问题。

    2.增加了代码的复杂度,当组合的层次过深的时候,代码的结构会很复杂。

    3.类型安全问题,当管理多个组件对象时,可能需要额外的类型转换编码。

    六,代码实战

    代码实战:基于组合模式实现的文件系统

    1. #include
    2. #include
    3. class FileSystemComponent {
    4. public:
    5. virtual void display() const = 0;
    6. };
    7. class File : public FileSystemComponent {
    8. public:
    9. File(const std::string& name, int size)
    10. : name(name), size(size)
    11. {
    12. }
    13. void display() const override
    14. {
    15. std::cout << "File: " << name <<
    16. " (" << size << " bytes)" <<
    17. std::endl;
    18. }
    19. private:
    20. std::string name;
    21. int size;
    22. };
    23. class Directory : public FileSystemComponent {
    24. public:
    25. Directory(const std::string& name)
    26. : name(name)
    27. {
    28. }
    29. void display() const override
    30. {
    31. std::cout << "Directory: " << name << std::endl;
    32. for (const auto& component : components) {
    33. component->display();
    34. }
    35. }
    36. void addComponent(FileSystemComponent* component)
    37. {
    38. components.push_back(component);
    39. }
    40. private:
    41. std::string name;
    42. std::vector components;
    43. };
    44. int main()
    45. {
    46. FileSystemComponent* file1
    47. = new File("document.txt", 1024);
    48. FileSystemComponent* file2
    49. = new File("image.jpg", 2048);
    50. Directory* directory = new Directory("My Documents");
    51. directory->addComponent(file1);
    52. directory->addComponent(file2);
    53. directory->display();
    54. return 0;
    55. }

    运行结果:

    1. Directory: My Documents
    2. File: document.txt (1024 bytes)
    3. File: image.jpg (2048 bytes)

    七,参考阅读

    https://refactoring.guru/design-patterns/composite
    https://www.geeksforgeeks.org/composite-method-software-design-pattern/
    https://www.geeksforgeeks.org/composite-design-pattern-in-java/
  • 相关阅读:
    【Elasticsearch】开源搜索技术的演进与选择:Elasticsearch 与 OpenSearch
    RTOS任务间通信为什么不用全局变量?
    Vue前后端交互、生命周期、组件化开发
    mac支持fat32格式吗 mac支持什么格式的移动硬盘
    1.4_29 Axure RP 9 for mac 高保真原型图 - 案例28【中继器-后台管理系统6】功能-原位修改数据
    java计算机毕业设计燕理快递中转站系统设计与实现MyBatis+系统+LW文档+源码+调试部署
    数学术语之源——纤维(fiber)
    x86下docker镜像中arm64v8/openjdk:8-jre添加vi/vim/ping/curl命令
    UML---用例图
    基于SSM的宠物医院管理系统
  • 原文地址:https://blog.csdn.net/CoderZZ_2024/article/details/139787675