文章目录

  • 一、引言
  • 二、模式原理分析
  • 三、代码示例
  • 四、核心要点
  • 五、使用场景分析
  • 六、案例
  • 七、为何使用组合模式?
  • 八、优缺点剖析
  • 九、最佳实践建议
  • 十、总结

在这里插入图片描述

一、引言

“组合模式”(Composite Pattern)常被误解为“组合关系”。前者专注于将对象组合成树形结构来表示“整体—部分”的层次,并允许客户端以一致方式处理单个对象和组合对象;后者仅指通过封装多种对象完成某个功能。尽管组合模式在日常项目中并不如装饰、代理那样频繁,但它对于处理复杂结构、理解框架源码、数据库索引等场景至关重要。


二、模式原理分析

定义:将对象组合成树形结构以表示整体—部分的层次结构,客户端可统一对待单个对象和组合对象。

  • 关键:

    1. 树形分层:组织节点形成多级结构。
    2. 统一操作:对叶子与组合节点调用同一接口。

下图为组合模式 UML:

«abstract»
Component
+operation()
Leaf
+operation()
Composite
-List<Component> children
+add(Component c)
+remove(Component c)
+getChild(int i) : Component
+operation()

角色说明:

  • 抽象组件(Component):定义公共接口(如 operation())。
  • 叶子节点(Leaf):树的最底层,不再有子节点,实现抽象组件接口。
  • 组合节点(Composite / Node):可包含子组件,维护子列表并在其操作中遍历调用子组件。

三、代码示例

// 抽象组件
public abstract class Component {public abstract void operation();
}// 叶子节点
public class Leaf extends Component {@Overridepublic void operation() {// 叶子节点具体操作逻辑}
}// 组合节点
public class Node extends Component {private List<Component> children = new ArrayList<>();@Overridepublic void operation() {// 遍历所有子节点,统一调用for (Component child : children) {child.operation();}}public void add(Component c) {children.add(c);}public void remove(Component c) {children.remove(c);}public Component getChild(int index) {return children.get(index);}
}

注意:遍历可能用递归、深度优先或广度优先,不必局限于简单for循环,具体算法可根据场景灵活选用。


四、核心要点

组合模式封装了:

  1. 叶子与组合节点的区别
  2. 真实结构的多种形态(树、环、双向链);
  3. 遍历算法的策略(深/广度、排序、过滤等);
  4. 操作策略(聚合、搜索、修改等)。

客户端只需面向统一接口,无需关心内部结构细节。


五、使用场景分析

  • 树形结构管理:组织架构、文件系统、商品订单层次。
  • 跨层级聚合统计:统计某部门或文件夹下所有子项的数据。
  • 统一操作集合:对结构中所有节点执行新增、删除、查找等相同行为。

示例:订单信息计算
订单包含商品、发票、包装盒,盒子中可嵌套更小盒子,结构呈“倒置树”。组合模式可递归累加每层节点的金额、促销与抵扣,使计算逻辑简洁一致。


六、案例

  • 公司组织架构:总经理→部门经理→组长→员工,各层均可“统计人数”“发放奖金”。
  1. 定义抽象组件 OrgComponent,声明统一操作:统计人数和发放奖金。
  2. 实现叶子节点 Employee,表示员工。
  3. 实现组合节点 Department,表示部门,可添加/移除子组件,并递归实现操作。
  4. 提供示例构建组织架构并执行操作。
// 抽象组件
public abstract class OrgComponent {protected String name;public OrgComponent(String name) {this.name = name;}// 统计该节点及子节点的总人数public abstract int countEmployees();// 按指定金额发放奖金public abstract void distributeBonus(double amount);
}// 叶子节点:员工
public class Employee extends OrgComponent {public Employee(String name) {super(name);}@Overridepublic int countEmployees() {return 1;  // 单个员工}@Overridepublic void distributeBonus(double amount) {System.out.printf("给员工 %s 发放奖金:%.2f 元%n", name, amount);}
}// 组合节点:部门/职位
public class Department extends OrgComponent {private List<OrgComponent> children = new ArrayList<>();public Department(String name) {super(name);}public void add(OrgComponent comp) {children.add(comp);}public void remove(OrgComponent comp) {children.remove(comp);}@Overridepublic int countEmployees() {int total = 0;for (OrgComponent comp : children) {total += comp.countEmployees();}return total;}@Overridepublic void distributeBonus(double amount) {System.out.printf("给部门 %s 总计 %.2f 元奖金,按人数平均分配:%d 人%n",name, amount, countEmployees());double perCapita = amount / countEmployees();for (OrgComponent comp : children) {comp.distributeBonus(perCapita);}}
}// 示例使用
public class CompanyDemo {public static void main(String[] args) {// 构建组织架构Department root = new Department("总经理");Department deptA = new Department("部门经理A");Department teamA1 = new Department("组长A1");teamA1.add(new Employee("张三"));teamA1.add(new Employee("李四"));Department teamA2 = new Department("组长A2");teamA2.add(new Employee("王五"));deptA.add(teamA1);deptA.add(teamA2);Department deptB = new Department("部门经理B");deptB.add(new Employee("赵六"));deptB.add(new Employee("钱七"));root.add(deptA);root.add(deptB);// 统计总人数System.out.println("公司总人数: " + root.countEmployees() + " 人");// 发放奖金 10000 元root.distributeBonus(10000.0);}
}

运行结果示例

公司总人数: 6 人
给部门 总经理 总计 10000.00 元奖金,按人数平均分配:6 人
给部门 部门经理A 总计 3333.33 元奖金,按人数平均分配:4 人
给部门 组长A1 总计 833.33 元奖金,按人数平均分配:2 人
给员工 张三 发放奖金:416.67 元
给员工 李四 发放奖金:416.67 元
给部门 组长A2 总计 833.33 元奖金,按人数平均分配:1 人
给员工 王五 发放奖金:833.33 元
给部门 部门经理B 总计 3333.33 元奖金,按人数平均分配:2 人
给员工 赵六 发放奖金:1666.67 元
给员工 钱七 发放奖金:1666.67 元
  • MySQL B+ 树索引:叶子节点存储数据指针,内部节点存储键与子节点指针,整个树结构即组合模式的典型应用,提升查询性能。

七、为何使用组合模式?

  1. 层次管理:按层级自然分类对象,如订单与子订单、文件夹与文件。
  2. 统一行为:客户端代码无需区分处理单个对象或组合,简化调用逻辑。
  3. 快速扩展:动态添加新节点或新类别,符合开闭原则,无需修改现有代码。

八、优缺点剖析

收益

  • 清晰分层,层次关系一目了然。
  • 客户端使用统一接口,无差异化处理代码。
  • 易于扩展,动态挂载节点类型。

损失

  • 类型约束难:无编译期限制,需运行时检查。
  • 额外检查成本:叶子与组合节点行为需抛出或忽略操作,增加实现复杂度。
  • 遍历性能风险:错误算法(多层嵌套循环)在大数据量下可能导致指数级开销。

九、最佳实践建议

  • 逻辑约束:在设计时明确节点类型与层级,避免任意组合。
  • 遍历算法:选择合适的深度或广度优先、迭代器模式或并行遍历,控制时间复杂度。
  • 异常处理:叶子节点对不支持的方法抛出 UnsupportedOperationException,并在客户端捕获或规避。

十、总结

组合模式通过树形结构与统一接口,将复杂对象层次简化为可递归处理的组件,大大提升代码灵活性与可扩展性。但需谨慎约束与优化遍历,否则会带来维护和性能成本。

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/web/92068.shtml
繁体地址,请注明出处:http://hk.pswp.cn/web/92068.shtml
英文地址,请注明出处:http://en.pswp.cn/web/92068.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

STM32U575低功耗调试

开启了MSIK时钟导致功耗变高在stop2模式下, 整体板子25.41uA; 如果在standby模式, 整体板子5uA;如果在stop2模式, 并且把LPTIM3,4选择的时钟是MSIK, 整体功耗53.59uA2.stanby模式板子整体5uA调试的时候, 可以让板子进入standby模式, 如果电流很小, 可以证明板子没有漏电(图画错…

基于ARM+FPGA多通道超声信号采集与传输系统设计

针对超声信号采集系统在多通道同步采集和高速数据传输所面临的挑战,设计并实现了一种 基于 FPGA 的8通道超声信号同步采集与传输系统。系统以FPGA 作为主控芯片,ADI公司的 AD9279作 为8通道超声信号同步采集的模拟前端和模数转换芯片,通过 DDR3SDRAM 及 USB3.0实现数据缓存和 高…

计算机网络:为什么IPv6没有选择使用点分十进制

IPv6没有采用点分十进制(如IPv4的192.168.1.1),核心原因是其地址长度、设计目标与表示需求和IPv4存在本质差异,而冒号分十六进制(如2001:0db8:85a3:0000:0000:8a2e:0370:7334)是更适配其特性的选择。具体可从以下几个角度分析: 一、地址长度差异:点分十进制无法适配12…

HBM Basic(VCU128)

目录 1. 简介 1.1 硬件平台 1.2 图片 2. 硬件信息 2.1 Vivado Basic 2.1.1 GPIO 2.1.2 Clock Sources 2.1.3 Reset 2.1.4 Flash 2.1.5 烧写报错 2.2 PCIe simple 2.2.1 Block Design 2.2.2 XDMA 2.3 PCIe HBM 2.3.1 Block Design 2.3.2 HBM IP 3. HBM 知识 3…

Mybatis的应用及部分特性

初识MybatisMybatis的概念MyBatis 是一个Java 持久层框架&#xff0c;核心作用是简化数据库操作&#xff0c;把 SQL 和 Java 代码解耦。ORM框架MyBatis是一个ORM 框架所谓ORM 框架&#xff0c;就是把数据库里的表、字段、关系&#xff0c;映射成编程语言里的类、属性、对象引用…

使用Jeecg低代码平台实现计划管控系统建设方案--2平台学习

1.前后端列表练习 前端页面下的views下的system下的基本都是系统管理的东西。 在system下新建一个目录edu。 index基本就是列表页面。 modal就是新增编辑弹窗。 api就是接口。 data就是列配置。 一些组件的使用可以参考官方文档&#xff0c;help.jeecg.com。 在创建一个…

调试|谷歌浏览器调试长连接|调试SSE和websocket

长连接需求不常有&#xff0c;控制台调试的细节容易忘&#xff0c;在这截图备忘。本文会记录SSE、websocket连接、普通接口 在谷歌浏览器控制台的对比 文章目录SSE&#xff08;Server-Sent Events&#xff09;观察对象&#xff1a;百度翻译观察请求头和响应头观察EventStream观…

VS2019 Qt5.14.2 OpenCV4.4.0 全流程安装及开发环境搭建与配置(工业相机环境配置)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录前言Visual Studio 2019 安装步骤项目配置验证Qt 5.14.2 安装步骤项目配置验证Visual Studio Qt 拓展&#xff08;确定项目后&#xff09;OpenCV 4.4.0 安装步骤项目…

正确配置jdk环境但IntelliJ IDEA无法启动

现象&#xff1a;今天突然发现开发工具双击没有正常启动&#xff0c;之前是用着的。问题排查&#xff1a;是否是因为jdk环境变量导致的&#xff0c;之前安装过安卓的开发环境也修改过环境变量。步骤一&#xff1a;cmd输入java -version 或javac&#xff0c;如图没有反应步骤二&…

ubuntu-server安装

1.下载系统镜像&#xff1a; 阿里云镜像站下载服务器镜像 https://mirrors.aliyun.com/ubuntu-releases/24.04/ubuntu-24.04.2-live-server-amd64.iso 1.创建新的虚拟机 按住键盘ctrl n 打开虚拟机创建界面 用光标选择对应语言没有中文哈 然后回车确认 设置计算机名、用户名…

Docker Compose管理新范式:可视化控制台结合cpolar提升容器编排效率?

文章目录前言1. 安装Docker2. 检查本地docker环境3. 安装cpolar内网穿透4. 使用固定二级子域名地址远程访问前言 在容器化应用部署领域&#xff0c;Docker Compose UI为开发者提供了一种更直观的解决方案。这款工具以Web界面形式封装了Docker Compose的核心功能&#xff0c;在…

BSW总结

1.FBL&#xff1a;【有道云笔记】BSW_FBL https://share.note.youdao.com/s/NaeZWTuR 2.NM: 【有道云笔记】BSW_NM https://share.note.youdao.com/s/MKxlIpUS

spring循环依赖解决

问题描述 spring循环依赖是对于ioc容器。类A、B、C&#xff0c;类A依赖了B&#xff0c;类A依赖了C&#xff0c;类B依赖了A&#xff0c;类C依赖了A。假如现在类A需要放到ioc&#xff0c;属性赋值的时候会去找B这个bean&#xff0c;但是B不存在&#xff0c;于是去创建B这个bean&a…

最新安卓原生对接苹果cms App后端+app(最新优化版)

内容目录一、详细介绍二、效果展示1.部分代码2.效果图展示三、学习资料下载一、详细介绍 一定要按照教程教的来搭建&#xff01; App演示图片 二、效果展示 1.部分代码 代码如下&#xff08;示例&#xff09;&#xff1a; public static function apkinfo(){return self::…

嵌入式硬件中运放的基本控制原理

上次课的最后是给大家总结一些基础电子知识的,我们接着往下讲。我们知道了运放的虚短虚断的概念理论上来说 可以进行计算了是吧。 这个图实际上是一个正输入信号的同相放大电路,我们看下如何计算,第一先看虚断。运放的输入脚内部对地是阻抗十分大是吧,那么这个正输入脚上的…

聚集索引与非聚集索引的区别

聚集索引&#xff08;Clustered Index&#xff09;和非聚集索引&#xff08;Non-Clustered Index&#xff09;是索引设计的核心概念&#xff0c;二者的本质区别体现在 与数据物理存储的关联方式 上&#xff0c;这种区别直接决定了它们的性能特性和适用场景。我们平时说的 聚簇索…

《零基础入门AI:传统机器学习进阶(从拟合概念到K-Means算法)》

一、欠拟合与过拟合欠拟合(Underfitting) 欠拟合是指模型在训练数据上表现不佳&#xff0c;同时在新的未见过的数据上也表现不佳。这通常发生在模型过于简单&#xff0c;无法捕捉数据中的复杂模式时。欠拟合模型的表现特征如下&#xff1a; 训练误差较高。测试误差同样较高。模…

Datawhale AI夏令营 第三期 task2 稍微改进

在打造基于大语言模型&#xff08;LLM&#xff09;文档检索的问答系统中&#xff0c;财经研报类文档是最具挑战的场景之一。它包含图文混排、精细定位需求&#xff08;页码、文件名&#xff09;、问题措辞高度多样化等一系列复杂性。 下面的内容是大模型辅助整理的&#xff1a;…

LeetCood算法题~水果成篮

水果成篮 你正在探访一家农场&#xff0c;农场从左到右种植了一排果树。这些树用一个整数数组 fruits 表示&#xff0c;其中 fruits[i] 是第 i 棵树上的水果 种类 。你想要尽可能多地收集水果。然而&#xff0c;农场的主人设定了一些严格的规矩&#xff0c;你必须按照要求采摘水…

【Lua】题目小练8

-- 题目 1&#xff1a;定义一个类 Person-- 属性&#xff1a;name、age&#xff0c;其中 age 默认是 0&#xff0c;不能小于 0。-- 方法&#xff1a;introduce()&#xff0c;输出 "My name is <name>, I am <age> years old."-- 要求使用封装思想&#x…