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

2023-11-16


使用场景

组合模式和类与类之间的组合是不同的概念。

组合模式主要用来处理树形结构的数据,如果要表达的数据不是树形结构,就不太适合组合模式。

比如我们有一个目录结构:
在这里插入图片描述

这个目录我们把它绘制成树形结构:
在这里插入图片描述

如何利用程序把这个目录结构给绘制出来呢?

我们可以创建一个文件类,用来保存普通文件,然后再创建一个目录类,这个目录类中有一个list来保存子目录和子文件:

namespace hjl_project1
{	
	//文件相关类
	class File
	{
	public:
		//构造函数
		File(string name) :m_sname(name) {}

		//显示文件名
		void ShowName(string lvlstr) //lvlstr:为了显示层次关系的缩进字符串内容
		{
			cout << lvlstr << "-" << m_sname << endl; //显示“-”代表是一个文件,属末端节点(不会再有子节点)
		}

	private:
		string m_sname; //文件名
	};

	//目录相关类
	class Dir
	{
	public:
		Dir(string name) :m_sname(name) {}

	public:
		//目录中可以增加其他文件
		void AddFile(File* pfile)
		{
			m_childFile.push_back(pfile);
		}
		//目录中可以增加其他目录
		void AddDir(Dir* pdir)
		{
			m_childDir.push_back(pdir);
		}

		//显示目录名,同时也要负责其下面的文件和目录名的显示工作
		void ShowName(string lvlstr)//lvlstr:为了显示层次关系的缩进字符串内容
		{
			//(1)输出本目录名
			cout << lvlstr << "+" << m_sname << endl; //显示“+”代表是一个目录,其中会包含其他内容

			//(2)输出所包含的文件名
			lvlstr += "    "; //本目录中的文件和目录的显示,要缩进一些来显示
			for (auto iter = m_childFile.begin(); iter != m_childFile.end(); ++iter)
			{
				(*iter)->ShowName(lvlstr); //显示文件名
			}

			//(3)输出所包含的目录名
			for (auto iter = m_childDir.begin(); iter != m_childDir.end(); ++iter)
			{
				(*iter)->ShowName(lvlstr); //显示目录名,这里涉及了递归调用 
			}
		}

	private:
		string m_sname; //目录名
		list<File*> m_childFile; //目录中包含的文件列表
		list<Dir*> m_childDir; //目录中包含的子目录列表
	};

}

然后创建出目录和文件,在父目录下添加子目录和文件即可:

int main()
{
	using namespace hjl_project1;
	//(1)创建各种目录,文件对象
	Dir *pdir1 = new Dir("root");
	//----
	File* pfile1 = new  File("common.mk");
	File* pfile2 = new  File("config.mk");
	File* pfile3 = new  File("makefile");
	//-----
	Dir* pdir2 = new Dir("app");
	File* pfile4 = new  File("nginx.c");
	File* pfile5 = new  File("ngx_conf.c");
	//-----
	Dir* pdir3 = new Dir("signal");
	File* pfile6 = new  File("ngx_signal.c");
	//-----
	Dir* pdir4 = new Dir("_include");
	File* pfile7 = new  File("ngx_func.h");
	File* pfile8 = new  File("ngx_signal.h");

	//(2)构造树形目录结构
	pdir1->AddFile(pfile1);
	pdir1->AddFile(pfile2);
	pdir1->AddFile(pfile3);
	//----
	pdir1->AddDir(pdir2);
		pdir2->AddFile(pfile4);
		pdir2->AddFile(pfile5);
	//----
	pdir1->AddDir(pdir3);
		pdir3->AddFile(pfile6);
	//----
	pdir1->AddDir(pdir4);
		pdir4->AddFile(pfile7);
		pdir4->AddFile(pfile8);


	//(3)输出整个目录结构,只要通过根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录显示。
	pdir1->ShowName(""); //缩进字符刚开始可以为空
	pdir2->ShowName("");

	//(4)释放资源
	delete pfile8;
	delete pfile7;
	delete pdir4;
	//----
	delete pfile6;
	delete pdir3;
	//----
	delete pfile5;
	delete pfile4;
	delete pdir2;
	//----
	delete pfile3;
	delete pfile2;
	delete pfile1;
	delete pdir1;
	
	return 0;
}

在这里插入图片描述

上面的例子存在一些问题,为了区分目录和文件我们引入了两种类,这种区分是比较多余的。

在组合模式中,不再将目录和文件两种类单独分开,而是引入新的抽象类提供公共接口,目录和文件两种类继承这个抽象类。

namespace hjl_project2
{
	//抽象父类FileSystem(抽象接口)
	class FileSystem
	{
	public:
		virtual void ShowName(int level) = 0; //显示名字,参数level用于表示显示的层次,用于显示对齐
		virtual int Add(FileSystem* pfilesys) = 0; //向当前目录中增加文件或者子目录
		virtual int Remove(FileSystem* pfilesys) = 0; //从当前目录中移除文件或者子目录
		
		virtual ~FileSystem() {} //做父类时析构函数应该为虚函数
	};

	//文件相关类
	class File :public FileSystem
	{
	public:
		//构造函数
		File(string name) :m_sname(name) {}
		//显示名
		virtual void ShowName(int level)
		{
			for (int i = 0; i < level; ++i)
			{
				cout << "    "; //显示若干个空格用于对齐
			}
			cout << "-" << m_sname << endl;
		}
		virtual int Add(FileSystem* pfilesys)
		{
			return -1;
		}
		virtual int Remove(FileSystem* pfilesys)
		{
			return -1;
		}

	private:
		string m_sname; //文件名
	};

	//目录相关类
	class Dir :public FileSystem
	{
	public:
		//构造函数
		Dir(string name) :m_sname(name) {}

		//显示名字
		virtual void ShowName(int level)
		{
			//(1)显示若干个空格用于对齐
			for (int i = 0; i < level; ++i) { cout << "    "; }
			//(2)输出本目录名
			cout << "+" << m_sname << endl;
			//(3)显示的层级向下走一级
			level++;
			//(4)输出所包含的子内容(可能是文件,也可能是目录)
			//遍历目录中的文件和子目录
			for (auto iter = m_child.begin(); iter != m_child.end(); ++iter)
			{
				(*iter)->ShowName(level);
			}
		}

		virtual int Add(FileSystem* pfilesys)
		{
			m_child.push_back(pfilesys);
			return 0;
		}

		virtual int Remove(FileSystem* pfilesys)
		{
			m_child.remove(pfilesys);
			return 0;
		}

	private:
		string m_sname; //文件名
		list<FileSystem*> m_child; //目录中包含的文件或者其他目录列表
	};
}
int main()
{
	using namespace hjl_project2;

	//(1)创建各种目录,文件对象
	FileSystem* pdir1 = new Dir("root");
	//----
	FileSystem* pfile1 = new  File("common.mk");
	FileSystem* pfile2 = new  File("config.mk");
	FileSystem* pfile3 = new  File("makefile");
	//-----
	FileSystem* pdir2 = new Dir("app");
	FileSystem* pfile4 = new  File("nginx.c");
	FileSystem* pfile5 = new  File("ngx_conf.c");
	//-----
	FileSystem* pdir3 = new Dir("signal");
	FileSystem* pfile6 = new  File("ngx_signal.c");
	//-----
	FileSystem* pdir4 = new Dir("_include");
	FileSystem* pfile7 = new  File("ngx_func.h");
	FileSystem* pfile8 = new  File("ngx_signal.h");

	//(2)构造树形目录结构
	pdir1->Add(pfile1);
	pdir1->Add(pfile2);
	pdir1->Add(pfile3);
	//----
	pdir1->Add(pdir2);
	pdir2->Add(pfile4);
	pdir2->Add(pfile5);
	//----
	pdir1->Add(pdir3);
	pdir3->Add(pfile6);
	//----
	pdir1->Add(pdir4);
	pdir4->Add(pfile7);
	pdir4->Add(pfile8);


	//(3)输出整个目录结构,只要通过根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录显示。
	pdir1->ShowName(0); //缩进字符刚开始可以为空
	//pdir2->ShowName("");

	//(4)释放资源
	delete pfile8;
	delete pfile7;
	delete pdir4;
	//----
	delete pfile6;
	delete pdir3;
	//----
	delete pfile5;
	delete pfile4;
	delete pdir2;
	//----
	delete pfile3;
	delete pfile2;
	delete pfile1;
	delete pdir1;

	return 0;
}

在这里插入图片描述

在这里插入图片描述


组合模式的定义

将一组对象(文件和目录)组织成属性结构以表示“部分整体”的层次结构(目录中包含文件和子目录),是的用户对蛋哥对象(文件)和组合对象(目录)的操作/使用/处理具有一致性(不用区分树叶和树枝,两者都有相同的接口)。

使用组合模式的前提是,具体的数据必须能够以树形结构的方式表示,数中包含了单个对象和组合对象。该模式专注于树形结构中蛋哥对象和组合对象的递归遍历。

主要有三种角色:

  1. 抽象组件:上面的filesystem类
  2. 叶子组件:file类
  3. 树枝组件:dir类,可以包含子节点,子节点可以是树枝也可以是树叶

组合模式的优点:

  1. 简化了代码的书写。
  2. 符合开闭原则,后续增加叶子组件或者树枝组件,只需要创建新类并继承抽象组件即可。
  3. 方便处理复杂的树形结构。

安全组合模式

上面的组合模式属于透明组合模式:在抽象组件中声明了所有用于管理和访问子节点的成员函数的实现手段。这也就意味着叶子组件和树枝组件都需要实现他们。

而安全组合模式:抽象组件中用于管理和访问子节点的成员函数被转移到了树枝组件中。

namespace hjl_project3
{
	class Dir;
	//抽象父类FileSystem(抽象接口)
	class FileSystem
	{
	public:
		virtual void ShowName(int level) = 0; //显示名字,参数level用于表示显示的层次,用于显示对齐

		virtual int countNumOfFiles() = 0; //统计目录下包含的文件个数
		
		virtual Dir* ifCompositeObj() { return nullptr; } //判断是否是一个树枝(组合对象)
		virtual ~FileSystem() {} //做父类时析构函数应该为虚函数
	};

	//文件相关类
	class File :public FileSystem
	{
	public:
		//构造函数
		File(string name) :m_sname(name) {}
		//显示名
		virtual void ShowName(int level)
		{
			for (int i = 0; i < level; ++i)
			{
				cout << "    "; //显示若干个空格用于对齐
			}
			cout << "-" << m_sname << endl;
		}		

		virtual int countNumOfFiles()//统计目录下包含的文件个数
		{
			return 1; //文件节点,做数量统计时按1计算
		}

	private:
		string m_sname; //文件名
	};

	//目录相关类
	class Dir :public FileSystem
	{
	public:
		//构造函数
		Dir(string name) :m_sname(name) {}

		//显示名字
		virtual void ShowName(int level)
		{
			//(1)显示若干个空格用于对齐
			for (int i = 0; i < level; ++i) { cout << "    "; }
			//(2)输出本目录名
			cout << "+" << m_sname << endl;
			//(3)显示的层级向下走一级
			level++;
			//(4)输出所包含的子内容(可能是文件,也可能是目录)
			//遍历目录中的文件和子目录
			for (auto iter = m_child.begin(); iter != m_child.end(); ++iter)
			{
				(*iter)->ShowName(level);
			}
		}

		int Add(FileSystem* pfilesys)
		{
			m_child.push_back(pfilesys);
			return 0;
		}

		int Remove(FileSystem* pfilesys)
		{
			m_child.remove(pfilesys);
			return 0;
		}

		virtual Dir* ifCompositeObj() { return this; }

		virtual int countNumOfFiles()//统计目录下包含的文件个数
		{
			int iNumOfFiles = 0;
			for (auto iter = m_child.begin(); iter != m_child.end(); ++iter)
			{
				iNumOfFiles += (*iter)->countNumOfFiles(); //递归调用
			}
			return iNumOfFiles;
		}

	private:
		string m_sname; //文件名
		list<FileSystem*> m_child; //目录中包含的文件或者其他目录列表
	};

}


int main()
{
	using namespace hjl_project3;

	//(1)创建各种目录,文件对象
	Dir* pdir1 = new Dir("root");
	//----
	FileSystem* pfile1 = new  File("common.mk");
	FileSystem* pfile2 = new  File("config.mk");
	FileSystem* pfile3 = new  File("makefile");
	//-----
	Dir* pdir2 = new Dir("app");
	FileSystem* pfile4 = new  File("nginx.c");
	FileSystem* pfile5 = new  File("ngx_conf.c");
	//-----
	Dir* pdir3 = new Dir("signal");
	FileSystem* pfile6 = new  File("ngx_signal.c");
	//-----
	Dir* pdir4 = new Dir("_include");
	FileSystem* pfile7 = new  File("ngx_func.h");
	FileSystem* pfile8 = new  File("ngx_signal.h");

	//(2)构造树形目录结构
	pdir1->Add(pfile1);
	pdir1->Add(pfile2);
	pdir1->Add(pfile3);
	//----
	pdir1->Add(pdir2);
	pdir2->Add(pfile4);
	pdir2->Add(pfile5);
	//----
	pdir1->Add(pdir3);
	pdir3->Add(pfile6);
	//----
	pdir1->Add(pdir4);
	pdir4->Add(pfile7);
	pdir4->Add(pfile8);


	//(3)输出整个目录结构,只要通过根目录的ShowName方法即可,每个子目录都有自己的ShowName方法负责自己旗下的文件和目录显示。
	pdir1->ShowName(0); //缩进字符刚开始可以为空
	//pdir2->ShowName("");

	cout<<"文件个数:"<<pdir1->countNumOfFiles()<<endl;

	//(4)释放资源
	delete pfile8;
	delete pfile7;
	delete pdir4;
	//----
	delete pfile6;
	delete pdir3;
	//----
	delete pfile5;
	delete pfile4;
	delete pdir2;
	//----
	delete pfile3;
	delete pfile2;
	delete pfile1;
	delete pdir1;

	return 0;
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

C++设计模式---组合模式 的相关文章

  • 我如何才能等待多个事情

    我正在使用 C 11 和 stl 线程编写一个线程安全队列 WaitAndPop 方法当前如下所示 我希望能够将一些内容传递给 WaitAndPop 来指示调用线程是否已被要求停止 如果 WaitAndPop 等待并返回队列的元素 则应返回
  • GLKit的GLKMatrix“列专业”如何?

    前提A 当谈论线性存储器中的 列主 矩阵时 列被一个接一个地指定 使得存储器中的前 4 个条目对应于矩阵中的第一列 另一方面 行主 矩阵被理解为依次指定行 以便内存中的前 4 个条目指定矩阵的第一行 A GLKMatrix4看起来像这样 u
  • 按成员序列化

    我已经实现了template
  • 秒表有最长运行时间吗?

    多久可以Stopwatch在 NET 中运行 如果达到该限制 它会回绕到负数还是从 0 重新开始 Stopwatch Elapsed返回一个TimeSpan From MSDN https learn microsoft com en us
  • 在哪里可以找到列出 SSE 内在函数操作的官方参考资料?

    是否有官方参考列出了 GCC 的 SSE 内部函数的操作 即 头文件中的函数 除了 Intel 的 vol 2 PDF 手册外 还有一个在线内在指南 https www intel com content www us en docs in
  • ASP.NET MVC:这个业务逻辑应该放在哪里?

    我正在开发我的第一个真正的 MVC 应用程序 并尝试遵循一般的 OOP 最佳实践 我正在将控制器中的一些简单业务逻辑重构到我的域模型中 我最近一直在阅读一些内容 很明显我应该将逻辑放在域模型实体类中的某个位置 以避免出现 贫血域模型 反模式
  • 如何使用 ICU 解析汉字数字字符?

    我正在编写一个使用 ICU 来解析由汉字数字字符组成的 Unicode 字符串的函数 并希望返回该字符串的整数值 五 gt 5 三十一 gt 31 五千九百七十二 gt 5972 我将区域设置设置为 Locale getJapan 并使用
  • 堆栈溢出:堆栈空间中重复的临时分配?

    struct MemBlock char mem 1024 MemBlock operator const MemBlock b const return MemBlock global void foo int step 0 if ste
  • 在 ASP.NET 5 中使用 DI 调用构造函数时解决依赖关系

    Web 上似乎充斥着如何在 ASP NET 5 中使用 DI 的示例 但没有一个示例显示如何调用构造函数并解决依赖关系 以下只是众多案例之一 http social technet microsoft com wiki contents a
  • C++ OpenSSL 导出私钥

    到目前为止 我成功地使用了 SSL 但遇到了令人困惑的障碍 我生成了 RSA 密钥对 之前使用 PEM write bio RSAPrivateKey 来导出它们 然而 手册页声称该格式已经过时 实际上它看起来与通常的 PEM 格式不同 相
  • 带动态元素的 WPF 启动屏幕。如何?

    我是 WPF 新手 我需要一些帮助 我有一个加载缓慢的 WPF 应用程序 因此我显示启动屏幕作为权宜之计 但是 我希望能够在每次运行时更改屏幕 并在文本区域中显示不同的引言 这是一个生产力应用程序 所以我将使用非愚蠢但激励性的引言 当然 如
  • 将多个表映射到实体框架中的单个实体类

    我正在开发一个旧数据库 该数据库有 2 个具有 1 1 关系的表 目前 我为每个定义的表定义了一种类型 1Test 1Result 我想将这些特定的表合并到一个类中 当前的类型如下所示 public class Result public
  • 如何设计以 char* 指针作为类成员变量的类?

    首先我想介绍一下我的情况 我写了一些类 将 char 指针作为私有类成员 而且这个项目有 GUI 所以当单击按钮时 某些函数可能会执行多次 这些类是设计的单班在项目中 但是其中的某些函数可以执行多次 然后我发现我的项目存在内存泄漏 所以我想
  • SolrNet连接说明

    为什么 SolrNet 连接的容器保持静态 这是一个非常大的错误 因为当我们在应用程序中向应用程序发送异步请求时 SolrNet 会表现异常 在 SolrNet 中如何避免这个问题 class P static void M string
  • 转发声明和包含

    在使用库时 无论是我自己的还是外部的 都有很多带有前向声明的类 根据情况 相同的类也包含在内 当我使用某个类时 我需要知道该类使用的某些对象是前向声明的还是 include d 原因是我想知道是否应该包含两个标题还是只包含一个标题 现在我知
  • 基于 OpenCV 边缘的物体检测 C++

    我有一个应用程序 我必须检测场景中某些项目的存在 这些项目可以旋转并稍微缩放 更大或更小 我尝试过使用关键点检测器 但它们不够快且不够准确 因此 我决定首先使用 Canny 或更快的边缘检测算法 检测模板和搜索区域中的边缘 然后匹配边缘以查
  • 混合 ExecutionContext.SuppressFlow 和任务时 AsyncLocal.Value 出现意外值

    在应用程序中 由于 AsyncLocal 的错误 意外值 我遇到了奇怪的行为 尽管我抑制了执行上下文的流程 但 AsyncLocal Value 属性有时不会在新生成的任务的执行范围内重置 下面我创建了一个最小的可重现示例来演示该问题 pr
  • IEnumreable 动态和 lambda

    我想在 a 上使用 lambda 表达式IEnumerable
  • 哪种 C 数据类型可以表示 40 位二进制数?

    我需要表示一个40位的二进制数 应该使用哪种 C 数据类型来处理这个问题 如果您使用的是 C99 或 C11 兼容编译器 则使用int least64 t以获得最大的兼容性 或者 如果您想要无符号类型 uint least64 t 这些都定
  • Windows 和 Linux 上的线程

    我在互联网上看到过在 Windows 上使用 C 制作多线程应用程序的教程 以及在 Linux 上执行相同操作的其他教程 但不能同时用于两者 是否存在即使在 Linux 或 Windows 上编译也能工作的函数 您需要使用一个包含两者的实现

随机推荐

  • vscode安装

    博客 https zhuanlan zhihu com p 106357123 https code visualstudio com download
  • [创业之路-47] :动态股权机制 -2- 多轮融资股权稀释后,大股东保留控制权的常见套路

    正常来说一个蒸蒸日上的公司或者被看好的公司 都要面临融资的问题 融资之后 股权就会发生比较大的变化 多轮融资之后呢 再次引进新的合伙人呢 那时候的股权肯定低于51 甚至低于34 这时候靠什么掌控公司 1 有限合伙平台模式GP VS LP 同
  • windows安装pm2

    pm2是开源的进程管理器 可用于管理您的nodejs项目等 前段时间看到同事使用到此工具 今日特地学习安装使用 安装流程如下 1 确保你电脑安装了npm 可以通过npm v命令查看 npm v 2 安装pm2 命令 npm install
  • 程序员代码打字练习题库

    创建一个新的txt文件 将本文内容全选 粘贴 保存 然后导入金山打字通 即可练习程序员常用词汇 推荐使用金山打字通 英文文章练习 自定义课程 导入txt文件 保存 接下来你就可以联系打字了 path class classpath publ
  • 绕过protected方法的调用(包级共享)

    A类在a包 package a import b B public class A protected void sys System out println A protected sys方法 public static void mai
  • [Activiti 资料]Activiti 画图工具(activiti-designer,actiBPM,activiti-app)

    1 eclipse eclipse的画流程工具 activiti designer 1 1 直接下载Eclipse 或者下载已经安装了activiti designer的eclipse 既然你下载到了 怎么也礼节性的感谢一下哈 链接 htt
  • ENVI入门系列教程---二、图像分析---13. 遥感动态监测

    every blog every motto God helps those who help themselves https blog csdn net weixin 39190382 type blog 0 前言 遥感变化检测就是从不
  • EasyExcel,让excel导入导出更加简单

    EasyExcel EasyExcel是一个基于Java的简单 省内存的读写Excel的开源项目 在尽可能节约内存的情况下支持读写百M的Excel github地址 https github com alibaba easyexcel JA
  • 数据降维算法

    文章目录 效果一览 文章概述 部分源码 参考资料 效果一览 文章概述 数据降维算法 Matlab 基于局部费歇尔判别 LFDA 的分类数据降维可视化 部分源码
  • OpenCV Android以及扩展模块opencv_contrib的编译

    OpenCV和OpenCV contrib模块4 5 x版本的编译 环境准备 Ubuntu 16 04 1 环境变量 export ANDROID HOME work android sdk export ANDROID NDK HOME
  • 【allegro 17.4软件操作保姆级教程一】软件操作环境设置

    个人主页 highman110 作者简介 一名硬件工程师 持续学习 不断记录 保持思考 输出干货内容 目录 1操作环境准备 1 1单位设置 1 2画布面积设置 1 3软件显示设置 1 4布局显示设置 1 5格点设置 1 6大十字光标设置 1
  • 什么场景应该用 MongoDB ?

    月初在云栖社区上发起了一个 MongoDB 使用场景及运维管理问题交流探讨 的技术话题 有近5000人关注了该话题讨论 这里就 MongoDB 的使用场景做个简单的总结 谈谈什么场景该用 MongoDB 很多人比较关心 MongoDB 的适
  • 华为OD机试(JAVA)真题 2023(汽水瓶\随机数\进制转换)

    系列文章目录 文章目录 系列文章目录 前言 一 1 汽水瓶 二 明明的随机数 前言 一 1 汽水瓶 某商店规定 三个空汽水瓶可以换一瓶汽水 允许向老板借空汽水瓶 但是必须要归还 小张手上有n个空汽水瓶 她想知道自己最多可以喝到多少瓶汽水 数
  • 运维岗位面试被问到的问题

    一 tcp ip 三次握手具体过程 二 静态路由动态路由里面有哪些协议 三 ip地址分类 四 iptabled 五 linu系统和windows系统的区别 六 linux软连接与硬链接的区别 七 Linux命令 八 如何将一个用户添加到某一
  • cocosCreator 之 ScrollView

    版本 3 4 0 参考 ScrollView组件 简介 ScrollView组件作为滚动容器来使用 它的实现通过ScrollBar组件来展示内容的位置和Mask组件显示指定区域 来保证有限的区域内显示更多的内容 它的构成部分 ScrollB
  • 史上功能最全的Java权限认证框架

    文章目录 Sa Token是什么 Sa Token 能做什么 代码示例 官网地址 sa token 使用示例 SpringBoot 环境 1 创建项目 2 设置jar包依赖 3 配置文件 4 启动类 5 运行 Sa Token是什么 sa
  • LeetCode 101:和你一起你轻松刷题(python版) 第 1 章 题目分类

    LeetCode 101 和你一起你轻松刷题 python版 注 作者 高畅 Chang Gao 原书为c 版本 解题思路清晰 知识点全面 是一本好书 翻译成python版本的解法可能未必是最优解法 由于本人是新手小白 算法实现是第一步 优
  • stm32+lwip(四):网页服务器测试

    ST官方有lwip的例程 下载地址如下 https www st com content st com en products embedded software mcus embedded software stm32 embedded
  • ubuntu 22.04 升级openssh9.4p1 ,openssl3.1.2,zlib1.2.13

    参考 https blog csdn net weixin 37534043 article details 120822689 https blog csdn net xujiamin0022016 article details 878
  • C++设计模式---组合模式

    文章目录 使用场景 组合模式的定义 安全组合模式 使用场景 组合模式和类与类之间的组合是不同的概念 组合模式主要用来处理树形结构的数据 如果要表达的数据不是树形结构 就不太适合组合模式 比如我们有一个目录结构 这个目录我们把它绘制成树形结构