news 2026/6/10 17:50:22

15.设计模式-组合模式

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
15.设计模式-组合模式

组合模式:将对象组合成树形结构以表示‘部分-整体’的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

组合模式的两种实现:

  • 透明方式:在Component中声明所有用来管理子对象的方法,其中包括Add、Remove等。这样实现Component接口的所有子类都具备了Add和Remove。这样做的好处就是叶节点和枝节点对于外界没有区别,它们具备完全一致的行为接口。但问题也很明显,因为Leaf类本身不具备Add()、Remove()方法的功能,所以实现它是没有意义的。
  • 安全方式:在Component接口中不去声明Add和Remove方法,那么子类的Leaf也就不需要去实现它,而是在Composite声明所有用来管理子类对象的方法,这样做就不会出现刚才提到的问题,不过由于不够透明,所以树叶和树枝类将不具有相同的接口,客户端的调用需要做相应的判断,带来了不便。

需求


为一家在全国许多城市都有分销机构的大公司做办公管理系统,总部有人力资源、财务、运营等部门。

需求分析

  • 希望总公司的组织结构,比如人力资源部、财务部的管理功能可以复用于分公司

代码

业务类

#include<stdio.h>#include<stdlib.h>#include<string.h>typedefstructCompany{char*name;void(*add)(structCompany*,structCompany*);void(*remove)(structCompany*,structCompany*);void(*display)(structCompany*,int);void(*lineOfDuty)(structCompany*);}Company;typedefstructConcreteCompany{Company base;Company**children;intchildrenNum;}ConcreteCompany;voidConcreteCompanyAdd(Company*obj,Company*child){((ConcreteCompany*)obj)->children[((ConcreteCompany*)obj)->childrenNum++]=child;}voidConcreteCompanyRemove(Company*obj,Company*child){intn=((ConcreteCompany*)obj)->childrenNum;for(inti=0;i<n;i++){if(strcmp(((ConcreteCompany*)obj)->children[i]->name,child->name)==0){free(((ConcreteCompany*)obj)->children[i]);((ConcreteCompany*)obj)->children[i]=((ConcreteCompany*)obj)->children[((ConcreteCompany*)obj)->childrenNum-1];((ConcreteCompany*)obj)->childrenNum--;break;}}}voidConcreteCompanyDisplay(Company*obj,intdepth){for(inti=0;i<depth;i++){printf("-");}printf("%s\n",obj->name);intn=((ConcreteCompany*)obj)->childrenNum;for(inti=0;i<n;i++){((ConcreteCompany*)obj)->children[i]->display(((ConcreteCompany*)obj)->children[i],depth+1);}}voidConcreteCompanyLineOfDuty(Company*obj){intn=((ConcreteCompany*)obj)->childrenNum;for(inti=0;i<n;i++){((ConcreteCompany*)obj)->children[i]->lineOfDuty(((ConcreteCompany*)obj)->children[i]);}}Company*InitConcreteCompany(char*name){ConcreteCompany*obj=(ConcreteCompany*)malloc(sizeof(ConcreteCompany));obj->childrenNum=0;// 假设最多10个子公司和部门obj->children=(Company**)malloc(sizeof(Company*)*10);obj->base.name=name;obj->base.add=ConcreteCompanyAdd;obj->base.remove=ConcreteCompanyRemove;obj->base.display=ConcreteCompanyDisplay;obj->base.lineOfDuty=ConcreteCompanyLineOfDuty;return(Company*)obj;}typedefstructHRDepartment{Company base;}HRDepartment;voidHRDepartmentDisplay(Company*obj,intdepth){for(inti=0;i<depth;i++){printf("-");}printf("%s\n",obj->name);}voidHRDepartmentLineOfDuty(Company*obj){printf("%s 员工招聘培训管理\n",obj->name);}Company*InitHRDepartment(char*name){HRDepartment*obj=(HRDepartment*)malloc(sizeof(HRDepartment));obj->base.display=HRDepartmentDisplay;obj->base.lineOfDuty=HRDepartmentLineOfDuty;obj->base.name=name;return(Company*)obj;}typedefstructFinanceDepartment{Company base;}FinanceDepartment;voidFinanceDepartmentDisplay(Company*obj,intdepth){for(inti=0;i<depth;i++){printf("-");}printf("%s\n",obj->name);}voidFinanceDepartmentLineOfDuty(Company*obj){printf("%s 公司财务收支管理\n",obj->name);}Company*InitFinanceDepartment(char*name){FinanceDepartment*obj=(FinanceDepartment*)malloc(sizeof(FinanceDepartment));obj->base.display=FinanceDepartmentDisplay;obj->base.lineOfDuty=FinanceDepartmentLineOfDuty;obj->base.name=name;return(Company*)obj;}

客户端

隐藏子部门和分公司的区别

intmain(){Company*root=InitConcreteCompany("北京总公司");root->add(root,InitHRDepartment("总公司人力资源部"));root->add(root,InitFinanceDepartment("总公司财务部"));Company*comp=InitConcreteCompany("上海华东分公司");comp->add(comp,InitHRDepartment("华东分公司人力资源部"));comp->add(comp,InitFinanceDepartment("华东分公司财务部"));root->add(root,comp);Company*comp1=InitConcreteCompany("南京办事处");comp1->add(comp1,InitHRDepartment("南京办事处人力资源部"));comp1->add(comp1,InitFinanceDepartment("南京办事处财务部"));comp->add(comp,comp1);Company*comp2=InitConcreteCompany("杭州办事处");comp2->add(comp2,InitHRDepartment("杭州办事处人力资源部"));comp2->add(comp2,InitFinanceDepartment("杭州办事处财务部"));comp->add(comp,comp2);printf("结构图:\n");root->display(root,0);printf("职责:\n");root->lineOfDuty(root);return0;}

客户端打印:

结构图: 北京总公司 -总公司人力资源部 -总公司财务部 -上海华东分公司 --华东分公司人力资源部 --华东分公司财务部 --南京办事处 ---南京办事处人力资源部 ---南京办事处财务部 --杭州办事处 ---杭州办事处人力资源部 ---杭州办事处财务部 职责: 总公司人力资源部 员工招聘培训管理 总公司财务部 公司财务收支管理 华东分公司人力资源部 员工招聘培训管理 华东分公司财务部 公司财务收支管理 南京办事处人力资源部 员工招聘培训管理 南京办事处财务部 公司财务收支管理 杭州办事处人力资源部 员工招聘培训管理 杭州办事处财务部 公司财务收支管理

UML图

总结

  • 组合模式使用场景?
    “当你发现需求中是体现部分与整体层次的结构时,以及你希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑用组合模式了。”
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/10 13:48:11

提升数据交换效率,Protocol Buffers 带你飞![特殊字符]

Protocol Buffers - 谷歌的数据交换格式 Protocol Buffers&#xff08;也称为protobuf&#xff09;是谷歌提供的一种语言无关、平台无关和可扩展的结构化数据序列化机制&#xff0c;广泛应用于数据交换和存储。本文将详细介绍Protocol Buffers的基本概念、安装步骤、在不同编程…

作者头像 李华
网站建设 2026/6/10 13:05:48

智能合同分析省钱方案:AI实体提取,比人工省时90%

智能合同分析省钱方案&#xff1a;AI实体提取&#xff0c;比人工省时90% 1. 为什么律所需要AI合同审查&#xff1f; 作为律所合伙人&#xff0c;您可能经常面临这样的困境&#xff1a;合同审查工作占据了团队大量时间&#xff0c;但人工逐条检查不仅效率低下&#xff0c;还容…

作者头像 李华
网站建设 2026/6/10 12:49:59

API安全检测傻瓜教程:AI模型云端一键部署,小白也能做攻防

API安全检测傻瓜教程&#xff1a;AI模型云端一键部署&#xff0c;小白也能做攻防 引言&#xff1a;为什么你需要关注API安全&#xff1f; 想象一下&#xff0c;你家的防盗门锁被破解了&#xff0c;小偷可以自由进出却不会触发警报——这就是API接口没有防护的真实写照。API作…

作者头像 李华
网站建设 2026/6/10 15:34:23

没Linux电脑怎么做AI安全?云端Web界面,Windows也能玩转

没Linux电脑怎么做AI安全&#xff1f;云端Web界面&#xff0c;Windows也能玩转 引言&#xff1a;Windows用户的AI安全困境 很多Windows用户在学习AI安全工具时都会遇到一个尴尬的问题&#xff1a;大多数专业的安全检测工具都基于Linux系统开发。传统解决方案要么是安装双系统…

作者头像 李华
网站建设 2026/6/10 13:22:37

AI侦测技术全景体验:10个模型任你测,1小时仅需1块钱

AI侦测技术全景体验&#xff1a;10个模型任你测&#xff0c;1小时仅需1块钱 引言&#xff1a;为什么你需要AI侦测技术评测环境&#xff1f; 作为研究院助理&#xff0c;当你需要整理AI侦测技术发展报告时&#xff0c;最头疼的问题是什么&#xff1f;是找不到合适的测试环境&a…

作者头像 李华
网站建设 2026/6/10 13:18:11

智能实体侦测省钱攻略:按秒计费云GPU,比本地搭建省万元

智能实体侦测省钱攻略&#xff1a;按秒计费云GPU&#xff0c;比本地搭建省万元 1. 为什么开发者需要云GPU方案 作为一名自由开发者&#xff0c;接到AI侦测项目时最头疼的就是硬件投入。以常见的RTX 4090显卡为例&#xff0c;单卡价格就达到1.5万元&#xff0c;而整个项目预算…

作者头像 李华