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

简介: 设计模式之组合模式(C++)

一、组合模式是什么?

      组合模式是一种结构型的软件设计模式,将对象组合成树形结构,以凸显“部分-整体”的层次结构,使客户端对单个对象和组合对象的操作具备一致性。


      组合模式和桥接模式都应用了组合的思想,不同之处在于:桥接模式侧重于同级别间的组合,如多个属性的组合,避免了类爆炸;组合模式侧重于部分和整体的组合,避免了单对象和组合对象的区别对待,那样会增加程序复杂度。


      组合模式的优点:


  1. 层次鲜明。凸显“部分-整体”的层次结构。
  2. 一致性。对叶子对象(单)和容器对象(组合)的操作具备良好一致性。
  3. 节点自由度高。在结构中按需自由添加节点。

      组合模式的缺点:


  1. 设计更抽象。
  2. 应用场景限制。

      组合模式一般分为透明式组合模式和安全式组合模式。


1)透明式组合模式:将公共接口封装到抽象节点中,所有节点具备一致行为。

2)安全式组合模式:各层次差异较大,使用不同操作时建议采用该模式。

二、透明式组合模式

2.1 结构图

      客户端即Main主函数,采用透明式,无需分辨节点是叶子还是容器,只需使用抽象节点。

2.2 代码示例

      场景描述:我要设计一个文件系统,在文件夹中可以添加删除文件或者文件夹。

//File.h
/****************************************************/
#pragma once
#include <iostream>
#include <list>
using namespace std;
// 抽象类-节点
class Node
{
public:
  // 构造函数
  explicit Node(string name) :m_name(name) {};
  // 析构函数
  virtual ~Node() {};
  // 添加
  virtual void add(Node *node) {};
  // 删除
  virtual void remove(Node *node) {};
  // 显示
  virtual void show(int space) {
    for (int i = 0; i < space; i++) {
      cout << "  ";
    }
    cout << m_name << endl;
  }
protected:
  string m_name;                                       // 名字
};
// 具体类-Word文件
class WordFile :public Node
{
public:
  // 构造函数
  explicit WordFile(string name) :Node(name) {};
  // 析构函数
  virtual ~WordFile() {};
};
// 具体类-文件夹
class Folder :public Node
{
public:
  // 构造函数
  explicit Folder(string name) :Node(name) {};
  // 析构函数
  virtual ~Folder() {
    nodeList.clear();
  }
  // 添加
  virtual void add(Node *node) {
    nodeList.emplace_back(node);
  }
  // 删除
  virtual void remove(Node *node) {
    nodeList.remove(node);
  }
  // 显示
  virtual void show(int space) {
    Node::show(space);
    space++;
    for (auto node : nodeList) {
      node->show(space);
    }
  }
private:
  list<Node*> nodeList;                                // 节点列表
};
//main.cpp
/****************************************************/
#include <iostream>
#include <string>
#include "File.h"
using namespace std;
int main()
{
  Node *f0 = new Folder("我的文件夹");
  // 文件夹1中放入Word2和Word3,并将文件夹1放入我的文件夹
  Node *f1 = new Folder("文件夹1");
  Node *w2 = new WordFile("Word2");
  Node *w3 = new WordFile("Word3");
  f1->add(w2);
  f1->add(w3);
  f0->add(f1);
  // 将Word1放入我的文件夹
  Node *w1 = new WordFile("Word1");
  f0->add(w1);
  // 显示我的文件夹中的内容
  f0->show(0);
  // 删除文件夹1中的Word2文件,再次显示我的文件夹中的内容
  f1->remove(w2);
  f0->show(0);
  // 删除指针并置空
  delete f0, f1, w1, w2, w3;
  f0 = nullptr;
  f1 = nullptr;
  w1 = nullptr;
  w2 = nullptr;
  w3 = nullptr;
  return 0;
}

程序结果如下。

      在上述示例中,我采用的都是抽象节点,因为抽象类中涵盖了几乎所有的行为。对外界(客户端)而言,叶子和容器的行为没有区别,它们的区别是不可见的也是透明的。但同样,这样的设计一定意义上也是不安全的,因为叶子不可能和容器有完全一致的行为,就像上文中文件夹的增删功能,文件是没有的,如果对文件进行文件夹的相关独特操作,要做相关的异常判断。


      该模式是组合模式中常用的,虽然它违背了设计模式中的接口隔离原则(只提供需要的接口,不需要的接口要屏蔽)。

三、安全式组合模式

3.1 结构图

      客户端即Main主函数,采用安全式,抽象类中只规定基础操作,而叶子和容器各自独有的操作将放在自身中完成,因此客户端在调用时无法直接使用抽象节点。

3.2 代码示例

      场景描述:我要设计一个文件系统,在文件夹中可以添加删除文件或者文件夹。

//File.h
/****************************************************/
#pragma once
#include <iostream>
#include <list>
using namespace std;
// 抽象类-节点
class Node
{
public:
  // 构造函数
  explicit Node(string name) :m_name(name) {};
  // 析构函数
  virtual ~Node() {};
  // 显示
  virtual void show(int space) = 0;
protected:
  string m_name;                                       // 名字
};
// 具体类-Word文件
class WordFile :public Node
{
public:
  // 构造函数
  explicit WordFile(string name) :Node(name) {};
  // 析构函数
  virtual ~WordFile() {};
  // 显示
  virtual void show(int space) {
    for (int i = 0; i < space; i++) {
      cout << "  ";
    }
    cout << m_name << endl;
  }
};
// 具体类-文件夹
class Folder :public Node
{
public:
  // 构造函数
  explicit Folder(string name) :Node(name) {};
  // 析构函数
  virtual ~Folder() {
    nodeList.clear();
  }
  // 添加
  void add(Node *node) {
    nodeList.emplace_back(node);
  }
  // 删除
  void remove(Node *node) {
    nodeList.remove(node);
  }
  // 显示
  virtual void show(int space) {
    for (int i = 0; i < space; i++) {
      cout << "  ";
    }
    cout << m_name << endl;
    space++;
    for (auto node : nodeList) {
      node->show(space);
    }
  }
private:
  list<Node*> nodeList;                                // 节点列表
};
//main.cpp
/****************************************************/
#include <iostream>
#include <string>
#include "File.h"
using namespace std;
int main()
{
  Folder *f0 = new Folder("我的文件夹");
  // 文件夹1中放入Word2和Word3,并将文件夹1放入我的文件夹
  Folder *f1 = new Folder("文件夹1");
  WordFile *w2 = new WordFile("Word2");
  WordFile *w3 = new WordFile("Word3");
  f1->add(w2);
  f1->add(w3);
  f0->add(f1);
  // 将Word1放入我的文件夹
  WordFile *w1 = new WordFile("Word1");
  f0->add(w1);
  // 显示我的文件夹中的内容
  f0->show(0);
  // 删除文件夹1中的Word2文件,再次显示我的文件夹中的内容
  f1->remove(w2);
  f0->show(0);
  // 删除指针并置空
  delete f0, f1, w1, w2, w3;
  f0 = nullptr;
  f1 = nullptr;
  w1 = nullptr;
  w2 = nullptr;
  w3 = nullptr;
  return 0;
}

     程序结果如下。

      在上述示例中,客户端无法直接使用抽象节点了,因为抽象节点中没有add和remove的操作,但这样更安全了,叶子和容器不会调用对方的功能进而触发异常。

      注意:该模式违背了依赖倒置原则(程序设计要依赖于抽象接口,不要依赖于具体实现)。

四、总结

      我尽可能用较通俗的话语和直观的代码例程,来表述我对组合模式的理解,或许有考虑不周到的地方,如果你有不同看法欢迎评论区交流!希望我举的例子能帮助你更好地理解组合模式。

      如果文章帮助到你了,可以点个赞让我知道,我会很快乐~加油!

相关文章
|
5月前
|
设计模式 JavaScript 前端开发
js设计模式【详解】—— 组合模式
js设计模式【详解】—— 组合模式
59 7
|
3月前
|
设计模式 Java
Java设计模式:组合模式的介绍及代码演示
组合模式是一种结构型设计模式,用于将多个对象组织成树形结构,并统一处理所有对象。例如,统计公司总人数时,可先统计各部门人数再求和。该模式包括一个通用接口、表示节点的类及其实现类。通过树形结构和节点的通用方法,组合模式使程序更易扩展和维护。
Java设计模式:组合模式的介绍及代码演示
|
3月前
|
设计模式 存储 安全
Java设计模式-组合模式(13)
Java设计模式-组合模式(13)
|
5月前
|
设计模式 C++
C++一分钟之-设计模式:工厂模式与抽象工厂
【7月更文挑战第14天】设计模式是解决软件设计问题的通用方案。工厂模式与抽象工厂模式是创建型模式,用于对象创建而不暴露创建逻辑。工厂模式推迟实例化到子类,但过度使用会增加复杂性。抽象工厂则创建相关对象族,但过度抽象可能造成不必要的复杂度。两者均应按需使用,确保设计灵活性。代码示例展示了C++中如何实现这两种模式。
47 3
|
5月前
|
设计模式 安全 C++
C++一分钟之-C++中的设计模式:单例模式
【7月更文挑战第13天】单例模式确保类只有一个实例,提供全局访问。C++中的实现涉及线程安全和生命周期管理。基础实现使用静态成员,但在多线程环境下可能导致多个实例。为解决此问题,采用双重检查锁定和`std::mutex`保证安全。使用`std::unique_ptr`管理生命周期,防止析构异常和内存泄漏。理解和正确应用单例模式能提升软件的效率与可维护性。
65 2
|
7月前
|
设计模式 开发框架 算法
C++中的设计模式:基本概念与应用
C++中的设计模式:基本概念与应用
72 2
|
6月前
|
设计模式 存储 安全
Java设计模式:组合模式之透明与安全的两种实现(七)
Java设计模式:组合模式之透明与安全的两种实现(七)
|
6月前
|
设计模式 Java
Java设计模式之组合模式详解
Java设计模式之组合模式详解
|
6月前
|
设计模式
组合模式-大话设计模式
组合模式-大话设计模式
|
7月前
|
设计模式 Java 容器
【设计模式系列笔记】组合模式
组合模式(Composite Pattern)是一种结构型设计模式,它允许将对象组合成树状结构以表示部分-整体的层次结构。组合模式使得客户端可以统一处理单个对象和对象组合,而无需区分它们的类型。
93 12

热门文章

最新文章

  • 1
    设计模式转型:从传统同步到Python协程异步编程的实践与思考
    59
  • 2
    C++一分钟之-设计模式:工厂模式与抽象工厂
    47
  • 3
    《手把手教你》系列基础篇(九十四)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-下篇(详解教程)
    54
  • 4
    C++一分钟之-C++中的设计模式:单例模式
    65
  • 5
    《手把手教你》系列基础篇(九十三)-java+ selenium自动化测试-框架设计基础-POM设计模式实现-上篇(详解教程)
    43
  • 6
    《手把手教你》系列基础篇(九十二)-java+ selenium自动化测试-框架设计基础-POM设计模式简介(详解教程)
    70
  • 7
    Java面试题:结合设计模式与并发工具包实现高效缓存;多线程与内存管理优化实践;并发框架与设计模式在复杂系统中的应用
    62
  • 8
    Java面试题:设计模式在并发编程中的创新应用,Java内存管理与多线程工具类的综合应用,Java并发工具包与并发框架的创新应用
    43
  • 9
    Java面试题:如何使用设计模式优化多线程环境下的资源管理?Java内存模型与并发工具类的协同工作,描述ForkJoinPool的工作机制,并解释其在并行计算中的优势。如何根据任务特性调整线程池参数
    52
  • 10
    Java面试题:请列举三种常用的设计模式,并分别给出在Java中的应用场景?请分析Java内存管理中的主要问题,并提出相应的优化策略?请简述Java多线程编程中的常见问题,并给出解决方案
    121