组合模式是一种结构型设计模式,它允许您将对象组合成树形结构,并以统一的方式处理它们。该模式基于递归组合的想法,其中一个组件可以由许多更小的组件组成,这些更小的组件可以由更小的组件组成,以此类推。

在组合模式中,有两种类型的组件:单个对象和组合对象。单个对象是组成树的最基本的对象,而组合对象则是由多个单个对象和组合对象组成的复杂对象。每个组件都有一个共同的接口,该接口定义了执行操作的方法。组合对象可以递归地调用它们的子组件来执行相同的操作。

组合模式的实际应用非常广泛。它通常用于处理树形结构,例如文件系统、GUI控件、公司组织结构等。在这些应用程序中,组合模式使您能够以递归的方式遍历树并访问所有组件。

组合模式的好处是它可以使代码更简洁,更具可读性。它也可以使您的代码更灵活,更易于扩展。通过将单个对象和组合对象组合成树形结构,您可以轻松地添加、删除或替换组件,而无需对整个系统进行修改。

好处

1. 统一处理组合对象和叶子对象

组合模式中,组合对象和叶子对象被一致对待,都是组件(Component),可以被统一处理。这意味着,我们可以不必区分处理一个叶子对象还是一个组合对象,从而简化了代码的复杂度。

2. 简化客户端代码

由于组合模式可以形成递归结构,因此可以很方便地对整个组合体系进行递归遍历。客户端可以通过一个接口调用整个组合结构,而不必递归遍历每个对象。这样可以大大简化客户端的代码。

3. 增加新的组件类很容易

组合模式的扩展性非常好。当需要增加新的组件类时,只需要扩展Component抽象类,并实现其中的方法即可。其他类都不需要修改,符合“开闭原则”。

此外,组合模式还可以使代码更易于维护。通过使用组合模式,您可以将复杂的树形结构拆分为多个简单的组件,并在需要时对每个组件进行修改。这样可以使代码更易于理解和维护,并且可以使您更容易找到和修复错误。

组合模式的缺点是它可能会导致某些操作的性能下降。由于组合对象包含许多单个对象和组合对象,因此在执行某些操作时可能会产生大量的递归调用,从而导致性能下降。此外,组合模式可能会使代码更加复杂,需要更多的代码来处理树形结构。

缺点

1. 可能过于抽象

组合模式把整个组合体系看成一棵树形结构,这种抽象方式可能导致程序员对实际情况的理解存在偏差。有时候,可能会出现把不应该组合的对象强行组合起来的情况,从而导致系统设计的混乱。

2. 难以限制组合中的组件类型

组合模式的一个缺点是,它难以限制组合中的组件类型。由于组合模式中的Component抽象类并没有定义具体的组件类型,因此我们无法通过类型检查来限制组件类型。如果组合结构中添加了错误的组件类型,运行时会导致错误。

我们以一个组织结构为例,来演示组合模式的实现。假设我们有一个组织结构,由公司、部门和员工组成。其中公司是一个整体,包含多个部门,每个部门又包含多个员工。我们可以使用组合模式来实现该组织结构的管理。

我们首先定义一个抽象类Component,它表示组合中的对象,可以是公司、部门或员工。

class Component {
public:virtual void add(Component* c) {}virtual void remove(Component* c) {}virtual void display(int depth) {}virtual ~Component() {}
};

然后我们定义三个具体的类,分别是Company、Department和Employee,它们继承自Component,并实现它们的具体功能。

class Company : public Component {
public:Company(std::string name) : m_name(name) {}void add(Component* c) override {m_components.push_back(c);}void remove(Component* c) override {m_components.erase(std::remove(m_components.begin(), m_components.end(), c), m_components.end());}void display(int depth) override {std::cout << std::string(depth, '-') << m_name << std::endl;for (auto& c : m_components) {c->display(depth + 2);}}
private:std::string m_name;std::vector<Component*> m_components;
};class Department : public Component {
public:Department(std::string name) : m_name(name) {}void add(Component* c) override {m_components.push_back(c);}void remove(Component* c) override {m_components.erase(std::remove(m_components.begin(), m_components.end(), c), m_components.end());}void display(int depth) override {std::cout << std::string(depth, '-') << m_name << std::endl;for (auto& c : m_components) {c->display(depth + 2);}}
private:std::string m_name;std::vector<Component*> m_components;
};class Employee : public Component {
public:Employee(std::string name) : m_name(name) {}void display(int depth) override {std::cout << std::string(depth, '-') << m_name << std::endl;}
private:std::string m_name;
};

最后,我们在客户端代码中使用这些类来构建组织结构。

int main() {// 创建公司对象Company* company = new Company("ABC Company");// 创建部门对象Department* department1 = new Department("Sales Department");Department* department2 = new Department("Finance Department");// 创建员工对象Employee* employee1 = new Employee("Alice");Employee* employee2 = new Employee("Bob");Employee* employee3 = new Employee("Charlie");Employee* employee4 = new Employee("David");// 将部门和员工添加到公司中company->add(department1);company->add(department2);department1->add(employee1);department1->add(employee2);department2->add(employee3);department2->add(employee4);// 显示组织结构company->display(0);return;
}

再用一个完整的代码示例,展示了如何使用组合模式创建树形结构:

#include <iostream>
#include <vector>
#include <string>// 抽象组件
class Component {
public:virtual ~Component() = default;virtual void operation() const = 0;virtual void add(Component*) {}virtual void remove(Component*) {}virtual Component* getChild(int) const { return nullptr; }
};// 叶子节点
class Leaf : public Component {
public:explicit Leaf(std::string name) : name_(std::move(name)) {}void operation() const override {std::cout << "Leaf " << name_ << " operation.\n";}private:std::string name_;
};// 组合节点
class Composite : public Component {
public:explicit Composite(std::string name) : name_(std::move(name)) {}void operation() const override {std::cout << "Composite " << name_ << " operation:\n";for (const auto& child : children_) {child->operation();}}void add(Component* component) override {children_.push_back(component);}void remove(Component* component) override {children_.erase(std::remove(children_.begin(), children_.end(), component), children_.end());}Component* getChild(int index) const override {if (index >= 0 && index < children_.size()) {return children_[index];}return nullptr;}private:std::string name_;std::vector<Component*> children_;
};int main() {auto leaf1 = new Leaf("leaf1");auto leaf2 = new Leaf("leaf2");auto leaf3 = new Leaf("leaf3");auto composite1 = new Composite("composite1");auto composite2 = new Composite("composite2");composite1->add(leaf1);composite1->add(leaf2);composite1->add(composite2);composite2->add(leaf3);composite1->operation();return 0;
}

在这个例子中,我们创建了一个简单的树形结构,其中 Composite 节点可以包含其他组件,包括其他 Composite 节点和 Leaf 节点。我们可以通过递归调用每个组件的 operation() 方法来执行操作。这个例子展示了组合模式的一个主要好处,即可以轻松地组合对象形成树形结构,而不需要知道这些对象的具体类型,从而提高了代码的灵活性和可扩展性。

不得不说的结构型模式-组合模式相关推荐

  1. Java设计模式之结构型:组合模式

    前言: 我们对于上面两幅图片肯定非常熟悉,这两幅图片我们都可以看做是一个文件结构,对于这样的结构我们称之为树形结构.在数据结构中我们知道可以通过调用某个方法来遍历整个树,当我们找到某个叶子节点后,就可 ...

  2. 【设计模式自习室】结构型:组合模式 Composite

    前言 <设计模式自习室>系列,顾名思义,本系列文章带你温习常见的设计模式.主要内容有: 该模式的介绍,包括: 引子.意图(大白话解释) 类图.时序图(理论规范) 该模式的代码示例:熟悉该模 ...

  3. 围观设计模式(16)--结构型之组合模式(Composite Pattern)

    组合模式也叫合成模式,有时又叫做部分-整体模式,主要是用来描述部分与整体的关系,其定义为:将对象组合成树形结构以表示"整体与部分"的层次结构,使得用户对单个对象和组合对象的使用具有 ...

  4. 【结构型】组合模式(Composite)

    目录 组合模式(Composite) 适用场景 组合模式实例代码(Java) 组合模式(Composite) 将对象组合成树型结构以表示"部分-整体"的层次结构.Composite ...

  5. Java设计模式之结构型:外观模式

    一.什么是外观模式: 外观模式通过对客户端提供一个统一的接口,用于访问子系统中的一群接口.使用外观模式有以下几点好处: (1)更加易用:使得子系统更加易用,客户端不再需要了解子系统内部的实现,也不需要 ...

  6. Java设计模式之结构型:代理模式

    前言: 我们一般在租房子时会去找中介,为什么呢?因为你对该地区房屋的信息掌握的不够全面,希望找一个更熟悉的人去帮你做:再比如我们打官司需要请律师,因为律师在法律方面有专长,可以替我们进行操作,表达我们 ...

  7. Java设计模式之结构型:桥接模式

    一.什么是桥接模式: 桥接,顾名思义,就是用来连接两个部分,使得两个部分可以互相通讯,桥接模式的作用就是为被分离的抽象部分和实现部分搭桥.在现实生活中一个物品在搭配不同的配件时会产生不同的动作和结果, ...

  8. 《设计模式详解》结构型模式 - 组合模式

    组合模式 5.6 组合模式 5.6.1 概述 5.6.2 结构 5.6.3 案例实现 5.6.4 组合模式的分类 5.6.5 优点 5.6.6 使用场景 完整的笔记目录:<设计模式详解>笔 ...

  9. JavaScript设计模式(三):结构型设计模式-外观模式、适配器模式、代理模式、装饰者模式、桥接模式、组合模式、享元模式

    JavaScript设计模式 - 结构型设计模式 套餐服务-外观模式 外观模式(Facade) 水管弯弯-适配器模式 适配器模式(Adapter) 适配异类框架 参数适配 牛郎织女-代理模式 代理模式 ...

  10. 设计模式(18):结构型-享元模式(Flyweight)

    设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...

最新文章

  1. java打字母小游戏总结与收获,java:打字母小游戏demo
  2. 前后台json交互,以及数据库json转换——PHPThinkphp5.1
  3. rJava安装及Java 开发R
  4. 浅谈==和equals
  5. 爬取 wallhaven图片到本地壁纸库
  6. 问题记录:模组屏调试点亮
  7. 【脑电信号】基于matlab小波变换DWT脑电信号ECG去噪【含Matlab源码 1622期】
  8. 解决Connectify和校园天翼宽带L2TP客户端的不兼容问题
  9. 什么是计算机病毒?中国黑客教父告诉你
  10. oracle 无效的窗口句柄 print spooler服务已开,大师为你解决win10系统无法运行print spooler服务的恢复技巧...
  11. 【CVPR2022】论文阅读:Revisiting Skeleton-based Action Recognition
  12. Linux上几款好用的字幕编辑器
  13. 每日codingame小游戏练习[2021.3.29](python3入门学习之rstrip方法)
  14. python +appium实现原理_Appium+python自动化(四十)-Appium自动化测试框架综合实践 - 代码实现(超详解)...
  15. 计算机信息安全法规和道德规范,信息安全法律法规与道德规范ppt
  16. 【生产者分析一】Kafka生产者流程【初探】
  17. JS将阿拉伯数字转为中文汉字
  18. cf服务器断开连接不稳定,cf与服务器断开连接
  19. 卡尔曼滤波公式推导(2)
  20. 医疗行业售前100问之第3问:医院的常用信息系统有哪些?

热门文章

  1. mysql 自定义函数 递归查找父节点
  2. 七彩智能组卷软件系统、
  3. 删除数据库 [MySQL][数据库]
  4. VB为报表盖电子图章
  5. Unity 之 OnGUI实时显示游戏FPS...
  6. C++ 头文件和源文件
  7. 必备redis6教程-分布式缓存Redis6.X+高可用集群课程介绍-小滴课堂
  8. STM32 USART使用奇偶校验位
  9. 《ArchSummit:从珍爱微服务框架看架构演进》
  10. python主程序流程图_用Python编程绘制流程图,你用过吗?