组合模式(结构型)
目录
一、前言
二、透明组合模式
三、安全组合模式
四、总结
一、前言
组合模式(Composite Pattern)是一种结构型设计模式,将对象组合成树形结构以表示“部分-整体”得层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
组合模式由以下角色组成:
Component(抽象组件):
一般是接口或者抽象类,是叶子构件和容器构件对象声明接口,抽象出访问以及管理子构件的方法,可以看做是根节点
Leaf(叶子结点):
在组合中表示叶子节点对象,叶子节点没有子节点,也就没有子构件
Composite(复合节点):
复合节点可以包含子节点,子节点可以是叶子节点,也可以是其他复合节点。可以看做是树枝节点
整个组合模式的结构图:
二、透明组合模式
组合模式分为透明和安全两种方式,在透明方式中,抽象组件中会声明所有类中的方法,客户端无法区别树叶对象和树枝对象,对客户端是透明的。但在树叶节点中,本来没有添加、删除放大,但却要实现它,是没有意义的。
比如公司组织建构,公司有总公司,总公司下有财务部门、技术部门等,还有分公司,分公司也有财务部门,技术部门等。如果按照传统方式,总公司的财务部门、技术部门等需要代码实现,分公司的财务部门、技术部门也需要代码实现,但现实中这些部门的职责差不多,分公司其实可以复用总公司的财务部门、技术部门类。
根据组合模式,我们便有以下代码实现:
抽象组件Component类,即根节点:
public abstract class Component {abstract void add(Component component);abstract void remove(Component component);abstract void display(int depth);abstract void operation();
}
复合节点Composite类,即树枝节点:
public class Composite extends Component{private List<Component> children = new ArrayList<>();private String name;public Composite(String name) {this.name = name;}@Overridevoid add(Component component) {children.add(component);}@Overridevoid remove(Component component) {children.remove(component);}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);for (Component component : children) {component.display(depth + 1);}}@Overridevoid operation() {for (Component component : children){component.operation();}}
}
叶子节点财务部门LeafOne类:
public class LeafOne extends Component{private String name;public LeafOne(String name) {this.name = name;}@Overridevoid add(Component component) {}@Overridevoid remove(Component component) {}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "财务操作");}
}
叶子节点财务部门LeafTwo类:
public class LeafTwo extends Component{private String name;public LeafTwo(String name) {this.name = name;}@Overridevoid add(Component component) {}@Overridevoid remove(Component component) {}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "技术操作");}
}
客户端调用类:
public class Client {public static void main(String[] args) {Component component = new Composite("北京总公司");component.add(new LeafOne("北京总公司财务部门"));component.add(new LeafTwo("北京总公司技术部门"));Component component1 = new Composite("上海分公司");component1.add(new LeafOne("上海分公司财务部门"));component1.add(new LeafTwo("上海分公司技术部门"));component.add(component1);Component component2 = new Composite("深圳分公司");component2.add(new LeafOne("深圳分公司财务部门"));component2.add(new LeafTwo("深圳分公司技术部门"));component.add(component2);System.out.println("公司架构:");component.display(1);System.out.println("职能:");component.operation();}
}
运行结果:
三、安全组合模式
相较于透明方式的组合模式,安全方式主要在抽象组件中不包含添加、删除操作,客户端调用中区分复合节点和叶子节点。
抽象组件Component类:
public abstract class Component {abstract void display(int depth);abstract void operation();
}
复合节点Composite类:
public class Composite extends Component{private List<Component> children = new ArrayList<>();private String name;public Composite(String name) {this.name = name;}public void add(Component component) {children.add(component);}public void remove(Component component) {children.remove(component);}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);for (Component component : children) {component.display(depth + 1);}}@Overridevoid operation() {for (Component component : children){component.operation();}}
}
叶子节点财务部门LeafOne类:
public class LeafOne extends Component {private String name;public LeafOne(String name) {this.name = name;}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "财务操作");}
}
叶子节点财务部门LeafTwo类:
public class LeafTwo extends Component{private String name;public LeafTwo(String name) {this.name = name;}@Overridevoid display(int depth) {System.out.println("深度:" + depth + " 名称:" + name);}@Overridevoid operation() {System.out.println(name + "技术操作");}
}
客户端调用:
public class Client {public static void main(String[] args) {Composite composite = new Composite("北京总公司");composite.add(new LeafOne("北京总公司财务部门"));composite.add(new LeafTwo("北京总公司技术部门"));Composite composite1 = new Composite("上海分公司");composite1.add(new LeafOne("上海分公司财务部门"));composite1.add(new LeafTwo("上海分公司技术部门"));composite.add(composite1);Composite composite2 = new Composite("深圳分公司");composite2.add(new LeafOne("深圳分公司财务部门"));composite2.add(new LeafTwo("深圳分公司技术部门"));composite.add(composite2);System.out.println("公司架构:");composite.display(1);System.out.println("职能:");composite.operation();}
}
运行结果:
四、总结
优点与缺点
优点:
1、高层模块(客户端)调用简单。组合模式使得客户端代码可以一致地处理单个对象和组合对象,无须关心自己处理的是单个对象,还是组合对象,这简化了客户端代码
2、节点自由增加,更容易在组合体内加入新的对象,客户端不会因为加入了新的对象而更改源代码,满足“开闭原则”
缺点:
1、在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
2、设计较复杂,客户端需要花更多时间理清类之间的层次关系
3、不容易限制容器中的构件
4、不容易用继承的方法来增加构件的新功能
使用场景:
当需求中是体现部分与整体层次的结构时,以及希望用户可以忽略组合对象与单个对象的不同,统一地使用组合结构中的所有对象时,就应该考虑组合模式。
Spring中IOC就使用到组合模式,通过将组件组合成树形结构,实现了对象的依赖关系管理和生命周期控制。比如Spring中的CompositeCacheManager,Spring用来管理多个CacheManager的复合类。
文件系统:
组合模式可以用来表示文件系统的层次结构,使得客户端可以以统一的方式操作文件和文件夹,例如创建、删除、移动等。
组织机构:
组合模式可以用于表示组织机构的层次结构,例如公司的组织结构可以以树形结构来表示,根节点表示公司,子节点表示部门,叶子节点表示员工。使用组合模式可以统一地管理公司的组织结构,例如添加、删除部门或员工,查找某个部门的员工等。
图形界面控件:
图形界面中的控件可以被看作是一个层次结构,例如窗口控件可以包含按钮控件和文本框控件,按钮控件又可以包含图片控件等。组合模式可以用来表示控件的层次结构,使得客户端可以以统一的方式操作控件,例如添加、删除、遍历等。
菜单和菜单项:
在图形界面中,菜单可以包含菜单项,菜单项可以是子菜单或者普通的操作项。组合模式可以用来表示菜单和菜单项的层次结构,使得客户端可以以统一的方式操作菜单和菜单项,例如添加、删除、遍历等。
相关文章:

组合模式(结构型)
目录 一、前言 二、透明组合模式 三、安全组合模式 四、总结 一、前言 组合模式(Composite Pattern)是一种结构型设计模式,将对象组合成树形结构以表示“部分-整体”得层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。 组合模式由以下角色组成…...

Pspice for TI学习
Pspice for TI中PSpice Part Search空白解决方法 配置环境变量 Cad_PSpice_TI_Regr_Srvr https://software-dl.ti.com/pspice/S009 重新安装2023版的Pspice Pspice安装链接 打开新安装的软件即可发现PSpice Part Search可以正常使用了 VSIN各参赛的含义 VOFF直流偏置VAMPL…...

LoRA的原理简介
在文章开始前先澄清一个概念,需要区分形近的单词"LoRa"(long range),这是一项通信技术。熟悉物联网行业的朋友相对会比较熟悉LoRa这项技术,因为有些设备比如电梯的控制就使用了这个技术进行本地数据和命令的…...

安卓使用Fiddler抓包 2024
简介 最近试了一下安卓使用fiddler 抓包,发现https包基本都会丢失。原因是Anandroid 7版本针对ssl安全性做了加强,不认可用户的证书。我们要做的就是把fiddler导出的证书进过处理后放置到系统证书目录下面,这样才能抓包https请求。 这里使用…...
【前端每日基础】day2 const var const的区别
var: 在早期的 JavaScript 中,var 是声明变量的唯一方式。它有以下特点: var 声明的变量是函数作用域(function-scoped),而不是块作用域(block-scoped),这意味着它们在整个函数内部都…...

乡村振兴的文化旅游融合:整合乡村文化资源与旅游资源,发展文化旅游产业,提升美丽乡村的文化内涵和旅游吸引力
一、引言 随着城市化进程的加速和人们精神文化需求的日益增长,乡村旅游逐渐成为旅游市场的新热点。乡村振兴战略的提出,为乡村旅游的发展提供了新的契机。在这一背景下,如何整合乡村文化资源与旅游资源,发展文化旅游产业…...
力扣题目101:对称二叉树
作者介绍:10年大厂数据\经营分析经验,现任大厂数据部门负责人。 会一些的技术:数据分析、算法、SQL、大数据相关、python 欢迎加入社区:码上找工作 作者专栏每日更新: LeetCode解锁1000题: 打怪升级之旅 python数据分析…...

struct和union大小计算规则
Union 一:联合类型的定义 联合也是一种特殊的自定义类型,这种类型定义的变量也包含一系列的成员,特征是这些成员公用同一块空间(所以联合也叫共用体) 比如:共用了 i 这个较大的空间 二: 联合的…...
数据库课程设计《基于Spring Boot + MyBatis + MySQL 实现Java医院药品管理系统》+源代码
文章目录 源代码下载地址项目介绍项目功能 项目备注源代码下载地址 源代码下载地址 点击这里下载源码 项目介绍 项目功能 库存管理 登记入库的药品。 登记出库的药品。 每日检查库存下限,报警。 每日检查过期的药品,报警并做退回销毁处理。 对有问题…...

【每日力扣】98. 验证二叉搜索树 与 108. 将有序数组转换为二叉搜索树
🔥 个人主页: 黑洞晓威 😀你不必等到非常厉害,才敢开始,你需要开始,才会变的非常厉害 98. 验证二叉搜索树 给你一个二叉树的根节点 root ,判断其是否是一个有效的二叉搜索树。 有效 二叉搜索树定义如下&a…...
Django3 个人开发笔记
查询函数 select_related 在 Django ORM 中,select_related 是一个查询性能优化工具,用于解决关联对象的查询效率问题。当你有两个通过外键(ForeignKey)或一对一字段(OneToOneField)连接的模型时…...

【全开源】Java U U跑腿同城跑腿小程序源码快递代取帮买帮送源码小程序+H 5+公众号跑腿系统
特色功能: 智能定位与路线规划:UU跑腿小程序能够利用定位技术,为用户提供附近的跑腿服务,并自动规划最佳路线,提高配送效率。订单管理:包括订单查询、订单状态更新、订单评价等功能,全行业覆盖…...

物联网实战--平台篇之(五)账户界面
目录 一、界面框架 二、首页(未登录) 三、验证码登录 四、密码登录 五、帐号注册 六、忘记密码 本项目的交流QQ群:701889554 物联网实战--入门篇https://blog.csdn.net/ypp240124016/category_12609773.html 物联网实战--驱动篇https://blog.csdn.net/ypp240124016/cat…...

9. Django Admin后台系统
9. Admin后台系统 Admin后台系统也称为网站后台管理系统, 主要对网站的信息进行管理, 如文字, 图片, 影音和其他日常使用的文件的发布, 更新, 删除等操作, 也包括功能信息的统计和管理, 如用户信息, 订单信息和访客信息等. 简单来说, 它是对网站数据库和文件进行快速操作和管…...
ELK+kafka日志采集
ElasticSeach(存储日志信息) Logstash(搬运工) Kibana 连接ElasticSeach图形化界面查询日志 ELK采集日志的原理: 在每个服务器上安装LogstashLogstash需要配置固定读取某个日志文件Logstash将日志文件格式化为json的…...
【C++ list所有函数举例如何使用】
C 中的 std::list 是一个双向链表,提供了在列表中添加、删除、访问元素等操作的方法。以下是一些常用的 std::list 函数以及如何使用它们的示例: push_back(const T& value): 在列表的末尾添加一个值为 value 的元素。 std::list<int> mylis…...

HTML5(1)
目录 一.HTML5(超文本(链接)标记(标签<>)语言) 1.开发环境(写代码,看效果) 2.vscode 使用 3.谷歌浏览器使用 4.标签语法 5.HTML基本骨架(网页模板) 6.标签的…...

【LAMMPS学习】八、基础知识(6.2)LAMMPS GitHub 教程
8. 基础知识 此部分描述了如何使用 LAMMPS 为用户和开发人员执行各种任务。术语表页面还列出了 MD 术语,以及相应 LAMMPS 手册页的链接。 LAMMPS 源代码分发的 examples 目录中包含的示例输入脚本以及示例脚本页面上突出显示的示例输入脚本还展示了如何设置和运行各…...
专业习惯:避开本地语言,使用通用语言
如果你的目标是走一步看一步,那躺平就得了,学习什么的都没有必要。如果你的目标是远方,那么就需要未雨绸缪。 在工作之中,本地语言及习惯固然可用,但非常局限,随便换一个地方和场景,别人就难以理…...

【Leetcode每日一题】 综合练习 - 逆波兰表达式求值(难度⭐⭐)(73)
1. 题目解析 题目链接:150. 逆波兰表达式求值 这个问题的理解其实相当简单,只需看一下示例,基本就能明白其含义了。 2.算法原理 数据结构选择: 使用栈(stack<int>)来存储操作数,以便进…...
在软件开发中正确使用MySQL日期时间类型的深度解析
在日常软件开发场景中,时间信息的存储是底层且核心的需求。从金融交易的精确记账时间、用户操作的行为日志,到供应链系统的物流节点时间戳,时间数据的准确性直接决定业务逻辑的可靠性。MySQL作为主流关系型数据库,其日期时间类型的…...

日语AI面试高效通关秘籍:专业解读与青柚面试智能助攻
在如今就业市场竞争日益激烈的背景下,越来越多的求职者将目光投向了日本及中日双语岗位。但是,一场日语面试往往让许多人感到步履维艰。你是否也曾因为面试官抛出的“刁钻问题”而心生畏惧?面对生疏的日语交流环境,即便提前恶补了…...

简易版抽奖活动的设计技术方案
1.前言 本技术方案旨在设计一套完整且可靠的抽奖活动逻辑,确保抽奖活动能够公平、公正、公开地进行,同时满足高并发访问、数据安全存储与高效处理等需求,为用户提供流畅的抽奖体验,助力业务顺利开展。本方案将涵盖抽奖活动的整体架构设计、核心流程逻辑、关键功能实现以及…...
Java 8 Stream API 入门到实践详解
一、告别 for 循环! 传统痛点: Java 8 之前,集合操作离不开冗长的 for 循环和匿名类。例如,过滤列表中的偶数: List<Integer> list Arrays.asList(1, 2, 3, 4, 5); List<Integer> evens new ArrayList…...

23-Oracle 23 ai 区块链表(Blockchain Table)
小伙伴有没有在金融强合规的领域中遇见,必须要保持数据不可变,管理员都无法修改和留痕的要求。比如医疗的电子病历中,影像检查检验结果不可篡改行的,药品追溯过程中数据只可插入无法删除的特性需求;登录日志、修改日志…...

深度学习习题2
1.如果增加神经网络的宽度,精确度会增加到一个特定阈值后,便开始降低。造成这一现象的可能原因是什么? A、即使增加卷积核的数量,只有少部分的核会被用作预测 B、当卷积核数量增加时,神经网络的预测能力会降低 C、当卷…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
C++.OpenGL (14/64)多光源(Multiple Lights)
多光源(Multiple Lights) 多光源渲染技术概览 #mermaid-svg-3L5e5gGn76TNh7Lq {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-3L5e5gGn76TNh7Lq .error-icon{fill:#552222;}#mermaid-svg-3L5e5gGn76TNh7Lq .erro…...
Java + Spring Boot + Mybatis 实现批量插入
在 Java 中使用 Spring Boot 和 MyBatis 实现批量插入可以通过以下步骤完成。这里提供两种常用方法:使用 MyBatis 的 <foreach> 标签和批处理模式(ExecutorType.BATCH)。 方法一:使用 XML 的 <foreach> 标签ÿ…...

视觉slam十四讲实践部分记录——ch2、ch3
ch2 一、使用g++编译.cpp为可执行文件并运行(P30) g++ helloSLAM.cpp ./a.out运行 二、使用cmake编译 mkdir build cd build cmake .. makeCMakeCache.txt 文件仍然指向旧的目录。这表明在源代码目录中可能还存在旧的 CMakeCache.txt 文件,或者在构建过程中仍然引用了旧的路…...