当前位置: 首页 > news >正文

用C语言实现组合模式

组合模式(Composite Pattern)的核心是将对象组合成树形结构,统一处理单个对象和组合对象,使客户端无需区分两者,可用一致的方式操作。在C语言中,可以通过结构体继承(模拟统一接口)+ 链表/数组(管理子对象) 实现:定义“组件”接口,叶子节点(单个对象)和容器节点(组合对象)都实现该接口,容器节点可包含子节点(叶子或其他容器)。

C语言实现组合模式的思路

  1. 抽象组件(Component):定义所有节点(叶子和容器)的统一接口(如operationaddremove等函数指针)。
  2. 叶子节点(Leaf):实现组件接口,代表不可再分的单个对象(无add/remove功能)。
  3. 容器节点(Composite):实现组件接口,内部包含子组件列表(叶子或其他容器),可管理子节点并递归调用其方法。

示例:文件系统(文件和文件夹的树形结构)

文件系统是组合模式的经典场景:

  • 文件夹(Folder):容器节点,可包含文件或其他文件夹。
  • 文件(File):叶子节点,不可包含子节点。
    两者都支持“显示信息”和“计算大小”的操作,客户端可统一处理。
步骤1:定义抽象组件(文件系统节点接口)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>// 抽象组件:文件系统节点接口
typedef struct FSComponent {char name[64]; // 节点名称(文件/文件夹名)// 统一操作:显示节点信息(递归显示子节点)void (*display)(struct FSComponent* self, int depth); // depth:缩进深度,用于树形显示// 统一操作:计算节点大小(文件大小/文件夹总大小)int (*get_size)(struct FSComponent* self);// 容器节点特有:添加子节点(叶子节点可设为NULL)void (*add)(struct FSComponent* self, struct FSComponent* child);// 容器节点特有:移除子节点void (*remove)(struct FSComponent* self, struct FSComponent* child);// 用于链表管理子节点(仅容器节点使用)struct FSComponent* next; // 下一个兄弟节点
} FSComponent;
步骤2:实现叶子节点(文件,File)

文件是不可再分的叶子节点,不支持add/remove,这两个方法可设为NULL或提示错误。

// 叶子节点:文件
typedef struct {FSComponent component; // 继承抽象组件int size;              // 文件大小(KB)
} File;// 文件的显示方法:打印文件名和大小
static void file_display(FSComponent* self, int depth) {// 打印缩进(树形结构)for (int i = 0; i < depth; i++) printf("  ");printf("- 文件: %s (大小: %dKB)\n", self->name, ((File*)self)->size);
}// 文件的大小计算:直接返回自身大小
static int file_get_size(FSComponent* self) {return ((File*)self)->size;
}// 创建文件(叶子节点)
FSComponent* file_create(const char* name, int size) {File* file = (File*)malloc(sizeof(File));if (!file) return NULL;// 初始化组件接口strncpy(file->component.name, name, sizeof(file->component.name)-1);file->component.display = file_display;file->component.get_size = file_get_size;file->component.add = NULL; // 叶子节点不支持添加子节点file->component.remove = NULL;file->component.next = NULL;// 初始化文件特有属性file->size = size;return (FSComponent*)file;
}
步骤3:实现容器节点(文件夹,Folder)

文件夹可包含多个子节点(文件或其他文件夹),通过链表管理子节点,并递归调用子节点的方法。

// 容器节点:文件夹
typedef struct {FSComponent component;   // 继承抽象组件FSComponent* children;   // 子节点链表(头指针)
} Folder;// 文件夹的显示方法:先显示自身,再递归显示所有子节点
static void folder_display(FSComponent* self, int depth) {Folder* folder = (Folder*)self;// 打印自身信息for (int i = 0; i < depth; i++) printf("  ");printf("+ 文件夹: %s\n", self->name);// 递归显示子节点(深度+1,增加缩进)FSComponent* child = folder->children;while (child) {child->display(child, depth + 1);child = child->next;}
}// 文件夹的大小计算:递归累加所有子节点的大小
static int folder_get_size(FSComponent* self) {Folder* folder = (Folder*)self;int total_size = 0;FSComponent* child = folder->children;while (child) {total_size += child->get_size(child); // 递归计算子节点大小child = child->next;}return total_size;
}// 文件夹添加子节点(链表头部插入)
static void folder_add(FSComponent* self, FSComponent* child) {if (!child) return;Folder* folder = (Folder*)self;// 新节点的next指向原头节点child->next = folder->children;// 头指针指向新节点folder->children = child;
}// 文件夹移除子节点(从链表中删除)
static void folder_remove(FSComponent* self, FSComponent* child) {if (!child) return;Folder* folder = (Folder*)self;FSComponent* prev = NULL;FSComponent* curr = folder->children;// 查找子节点并从链表中删除while (curr) {if (curr == child) {if (prev) {prev->next = curr->next; // 前节点指向后节点} else {folder->children = curr->next; // 头节点更新}curr->next = NULL; // 断开被移除节点的链接break;}prev = curr;curr = curr->next;}
}// 创建文件夹(容器节点)
FSComponent* folder_create(const char* name) {Folder* folder = (Folder*)malloc(sizeof(Folder));if (!folder) return NULL;// 初始化组件接口strncpy(folder->component.name, name, sizeof(folder->component.name)-1);folder->component.display = folder_display;folder->component.get_size = folder_get_size;folder->component.add = folder_add;folder->component.remove = folder_remove;folder->component.next = NULL;// 初始化子节点链表(空)folder->children = NULL;return (FSComponent*)folder;
}
步骤4:使用组合模式(统一操作树形结构)

客户端可通过抽象组件接口FSComponent统一操作文件和文件夹,无需区分类型。

int main() {// 1. 创建叶子节点(文件)FSComponent* file1 = file_create("笔记.txt", 10);FSComponent* file2 = file_create("图片.jpg", 200);FSComponent* file3 = file_create("数据.csv", 50);// 2. 创建容器节点(文件夹)FSComponent* docs_folder = folder_create("文档");FSComponent* pics_folder = folder_create("图片");FSComponent* root_folder = folder_create("根目录");// 3. 组合树形结构docs_folder->add(docs_folder, file1);    // 文档文件夹添加笔记.txtdocs_folder->add(docs_folder, file3);    // 文档文件夹添加数据.csvpics_folder->add(pics_folder, file2);    // 图片文件夹添加图片.jpgroot_folder->add(root_folder, docs_folder); // 根目录添加文档文件夹root_folder->add(root_folder, pics_folder); // 根目录添加图片文件夹// 4. 统一操作:显示整个树形结构(从根目录开始)printf("文件系统结构:\n");root_folder->display(root_folder, 0); // depth=0(无缩进)// 5. 统一操作:计算总大小printf("\n根目录总大小: %dKB\n", root_folder->get_size(root_folder));// 6. 清理内存(简化处理,实际需递归释放所有节点)free(file1);free(file2);free(file3);free(docs_folder);free(pics_folder);free(root_folder);return 0;
}

输出结果

文件系统结构:
+ 文件夹: 根目录+ 文件夹: 图片- 文件: 图片.jpg (大小: 200KB)+ 文件夹: 文档- 文件: 数据.csv (大小: 50KB)- 文件: 笔记.txt (大小: 10KB)根目录总大小: 260KB

核心思想总结

  1. 树形结构统一处理:无论是单个文件(叶子)还是文件夹(容器),客户端都通过FSComponent接口操作,无需区分类型(如displayget_size对两者都适用)。
  2. 递归组合:容器节点可包含其他容器节点(如“根目录”包含“文档”文件夹),形成多级树形结构,且操作可递归传递(如文件夹的get_size会递归计算所有子节点大小)。
  3. 灵活性:新增节点类型(如“压缩文件”)时,只需实现FSComponent接口,现有客户端代码无需修改,符合开放-封闭原则

C语言通过结构体继承(FileFolder包含FSComponent)和链表管理子节点,完美模拟了组合模式的核心,适合处理树形结构场景(如文件系统、组织架构、UI组件树等)。

http://www.dtcms.com/a/508238.html

相关文章:

  • 石家庄哪里有网站推广深圳网站建设开发哪家好
  • C#开发学习杂笔(更新中)
  • 【JAVA】实体类注解不持久化至数据库
  • 【Java 开发工程师面试场景题大全】
  • 站长推荐跳转福州网站制作维护服务
  • 垂直网站建设规模项目推广方案怎么写
  • 物联网如何重塑现代物流?从“货物运输”到“智能供应链”的变革!
  • 网站申请支付宝支付html网站的设计
  • Process Monitor 学习笔记(5.17):常见问题 性能调优(FAQ + Best Practices)
  • 从零开始学像素画——第三章 1.3像素画明暗
  • 如何有效应对企业数据爆炸式增长?群晖 RS4017xs+私有云存储有办法
  • 自适应检索增强生成(Adaptive RAG):智能问答的新范式
  • Python3 正则表达式详解
  • 智慧养老照护实训室沉浸式教学场景搭建与护理人才培养路径
  • YOLOv3目标检测算法深度解析:从核心改进到实战应用
  • Web前端开发工具实战指南 从开发到调试的完整提效方案
  • 济南网站设计公司富wordpress不兼容ie
  • ajax做购物网站燕郊做网站的公司
  • java求职学习day44
  • 5-5〔OSCP ◈ 研记〕❘ SQL注入攻击▸手动滥用SQLi实现提权
  • HTML应用指南:利用POST请求获取中国一汽红旗门店位置信息
  • 网站备案多久一次中国建设银行e路通网站
  • 怎么建手机网站美工设计培训网
  • 九、WEB APIs(四)
  • DDL与DML解析
  • 网站推广公司网站北京公司地址推荐
  • 如何免费建造网站做外贸网站要什么条件
  • 国产化Word处理控件Spire.Doc教程:用Java实现TXT文本与Word互转的完整教程
  • 用C语言实现建造者模式
  • 山亭网站建设工商网站