【设计模式精讲 Day 8】组合模式(Composite Pattern)


开篇

在“设计模式精讲”系列的第8天,我们将深入讲解组合模式(Composite Pattern)。组合模式是一种结构型设计模式,它允许将对象组合成树形结构以表示“整体-部分”的层次关系。通过这种模式,客户端可以统一地处理单个对象和对象组合,从而简化了复杂结构的操作。

组合模式的核心思想是:将对象组织成树状结构,使得客户端无需区分是处理单个对象还是对象集合。这在文件系统、菜单系统、图形界面等需要层级结构的场景中非常常见。

本文将从模式定义、结构、适用场景、实现方式、工作原理、优缺点分析等方面全面解析组合模式,并结合实际代码和案例说明其在Java开发中的应用价值。


模式定义

组合模式(Composite Pattern) 是一种结构型设计模式,它允许你将对象组合成树形结构以表示“整体-部分”的层次结构。组合模式让客户端可以统一地处理单个对象和对象组合,而无需关心它们的具体类型。

核心思想是:

  • 将对象组织成树状结构
  • 客户端可以一致地操作单个对象和对象组合
  • 通过递归结构简化复杂系统的管理

模式结构

组合模式通常包含以下几个关键角色:

角色名称说明
Component定义对象的公共接口,既可以是叶子节点,也可以是容器节点
Leaf叶子节点,不包含子节点,直接实现Component接口
Composite容器节点,包含多个Component子节点,实现对子节点的增删改查操作

UML类图文字描述

  • Component 是抽象类或接口,定义了所有节点共有的方法。
  • LeafComponent 的具体实现,代表叶子节点。
  • Composite 也是 Component 的具体实现,但内部维护了一个 List<Component> 来保存子节点。

适用场景

组合模式适用于以下几种典型场景:

场景描述
文件系统文件夹与文件的嵌套结构,如Windows资源管理器
图形用户界面菜单项、子菜单、主菜单的层级结构
组织架构公司部门、子公司、员工的层级关系
表达式求值数学表达式的树形结构,如算术运算符的组合
配置管理多层配置项的组合结构,如XML/JSON解析

实现方式

下面是一个完整的Java实现示例,展示了如何用组合模式构建一个简单的文件系统模型。

import java.util.ArrayList;
import java.util.List;// Component 接口
interface FileSystemNode {void display(int depth);
}// Leaf 类:文件
class File implements FileSystemNode {private String name;public File(String name) {this.name = name;}@Overridepublic void display(int depth) {// 输出缩进for (int i = 0; i < depth; i++) {System.out.print("  ");}System.out.println("File: " + name);}
}// Composite 类:文件夹
class Folder implements FileSystemNode {private String name;private List<FileSystemNode> children = new ArrayList<>();public Folder(String name) {this.name = name;}public void add(FileSystemNode node) {children.add(node);}public void remove(FileSystemNode node) {children.remove(node);}@Overridepublic void display(int depth) {// 输出当前文件夹名称for (int i = 0; i < depth; i++) {System.out.print("  ");}System.out.println("Folder: " + name);// 递归输出子节点for (FileSystemNode child : children) {child.display(depth + 1);}}
}

使用示例

public class CompositePatternDemo {public static void main(String[] args) {// 创建根目录Folder root = new Folder("Root");// 创建子文件夹Folder documents = new Folder("Documents");Folder pictures = new Folder("Pictures");// 添加文件documents.add(new File("report.docx"));documents.add(new File("notes.txt"));pictures.add(new File("photo1.jpg"));pictures.add(new File("photo2.jpg"));// 将子文件夹添加到根目录root.add(documents);root.add(pictures);// 显示整个结构root.display(0);}
}

单元测试(JUnit 5 示例)

import org.junit.jupiter.api.Test;import static org.junit.jupiter.api.Assertions.*;class CompositePatternTest {@Testvoid testFileSystemStructure() {Folder root = new Folder("Root");Folder documents = new Folder("Documents");Folder pictures = new Folder("Pictures");documents.add(new File("report.docx"));documents.add(new File("notes.txt"));pictures.add(new File("photo1.jpg"));pictures.add(new File("photo2.jpg"));root.add(documents);root.add(pictures);assertNotNull(root);assertEquals(2, root.children.size());}
}

工作原理

组合模式通过递归结构来处理复杂的层次结构。其底层机制如下:

  1. 统一接口:无论是叶子节点还是容器节点,都实现了相同的接口(FileSystemNode),因此客户端可以统一调用 display() 方法。
  2. 递归遍历:当访问一个容器节点时,会递归地访问其子节点,直到所有节点都被处理。
  3. 隐藏复杂性:客户端不需要知道当前操作的是单个对象还是对象集合,只需调用相同的方法即可。

优缺点分析

优点缺点
简化客户端代码,统一处理单个对象和组合对象增加了系统的复杂性,可能造成过度设计
便于扩展,新增节点类型只需继承Component需要确保每个子类正确实现接口方法
提高代码复用性,避免重复代码对于简单结构可能显得冗余

案例分析:企业级文件管理系统

在某企业的文件管理系统中,用户需要查看和管理多级文件夹结构。该系统使用组合模式构建了以下结构:

  • 根目录(Root)
  • 多个一级文件夹(如“项目A”、“项目B”)
  • 每个项目文件夹下有二级文件夹(如“文档”、“代码”、“图片”)
  • 每个二级文件夹中包含具体的文件

问题描述

传统做法是为每种类型的节点编写不同的处理逻辑,导致代码臃肿且难以维护。

解决方案

采用组合模式后,系统通过统一的 FileSystemNode 接口进行操作,无论当前处理的是文件还是文件夹,都可以使用相同的 display() 方法进行显示,极大简化了代码逻辑。


与其他模式的关系

组合模式常与其他设计模式配合使用,例如:

模式用途关联方式
迭代器模式遍历组合结构中的元素可以在Composite中加入Iterator接口
访问者模式对组合结构中的元素进行操作访问者可以访问Composite及其子节点
装饰器模式动态地给对象添加职责在Composite基础上动态增强功能
策略模式支持不同行为的切换可用于Composite中子节点的行为控制

总结

今天学习了组合模式(Composite Pattern),它是一种结构型设计模式,能够将对象组织成树形结构,使客户端可以统一处理单个对象和对象组合。我们从模式定义、结构、适用场景、实现方式、工作原理、优缺点分析等方面进行了详细讲解,并提供了完整的Java代码示例。

组合模式在文件系统、图形界面、配置管理等场景中广泛应用,体现了面向对象设计原则中的单一职责原则开闭原则,同时支持灵活的扩展。


下一讲预告

明天我们将进入行为型模式的第一天,讲解责任链模式(Chain of Responsibility Pattern)。该模式通过将请求的发送者和接收者解耦,使得多个对象都有机会处理请求,形成一条处理链。


文章简述

本文系统讲解了设计模式中的组合模式(Composite Pattern),从理论到实践,全面剖析了其核心思想、结构组成、适用场景以及Java实现方式。通过构建一个文件系统模型,展示了组合模式如何将对象组织成树形结构,并统一处理单个对象和对象组合。文章还结合真实项目案例,说明了组合模式在实际开发中的价值,并与其他设计模式进行了对比分析。最后,总结了该模式的优缺点及适用范围,帮助开发者在实际项目中合理运用这一设计模式。


进一步学习资料

  1. Design Patterns: Elements of Reusable Object-Oriented Software - GoF经典著作
  2. Refactoring Guru - Composite Pattern
  3. Java Design Patterns - Composite Pattern
  4. GeeksforGeeks - Composite Design Pattern in Java
  5. Wikipedia - Composite pattern

核心设计思想总结

组合模式的核心思想是将对象组织成树形结构,使客户端可以统一处理单个对象和对象组合。在实际项目中,它特别适合处理具有层级结构的业务场景,如文件系统、菜单系统、图形界面等。通过组合模式,我们可以提高代码的可维护性和扩展性,避免重复代码,提升系统的灵活性和可读性。

在实际开发中,建议在遇到需要处理“整体-部分”关系的场景时优先考虑组合模式。结合其他设计模式(如迭代器、访问者)可以进一步增强其功能,使其更适应复杂业务需求。

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

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

相关文章

【Dify学习笔记】:RagFlow接入Dify基础教程

RagFlow接入Dify基础教程 如果RagFlow还没部署&#xff0c;可参考我另一篇本地部署文章&#xff1a;【Dify学习笔记】&#xff1a;本地部署RagFlow适配Dify 一、RagFlow 1. 配置模型 点击&#xff1a;头像 > Model providers 添加模型供应商、设置默认模型Set default …

Apache ECharts-02.入门案例

一.入门案例 官网下载&#xff1a;下载 - Apache ECharts&#xff0c;下载echarts.js文件&#xff0c;下载好后在其同一个文件夹下创建html文件即可。 <!DOCTYPE html> <html><head><meta charset"utf-8" /><title>ECharts</title…

社群经济视阈下开源AI智能名片链动2+1模式与S2B2C商城小程序在私域电商中的融合应用研究

摘要&#xff1a;在数字经济与社交网络深度融合的背景下&#xff0c;付费社群凭借精准用户筛选、高价值成员聚合及强信任关系链等优势&#xff0c;成为私域电商发展的核心载体。本文基于社群经济理论&#xff0c;结合“开源AI智能名片链动21模式S2B2C商城小程序”的技术与商业逻…

【Tools】Mac brew工具

Homebrew&#xff08;简称 brew&#xff09;是 macOS&#xff08;也支持 Linux&#xff09;上的一款 包管理工具&#xff0c;它的作用类似于&#xff1a; Ubuntu 下的 aptCentOS 下的 yumArch Linux 下的 pacman 一句话概括&#xff1a; brew 是用来在 macOS 上安装、管理软件…

IEEE RAL 双臂机器人三连抓估计物体状态 无需特制夹爪或视觉相机 - 大阪大学万伟伟老师团队

IEEE RA-L | 万伟伟老师团队提出双臂机器人规划控制方法有效降低被抓物姿态不确定性 日本大阪大学万伟伟老师团队针对双臂机器人开发了一种重复抓取规划和阻抗控制的方法&#xff0c;该方法通过两个机械臂依次寻找抓取位置和物体姿态&#xff0c;并通过三个正交抓取动作&#x…

AtomicInteger 和 volatile Integer对比

AtomicInteger 和 volatile Integer 虽然都与线程安全有关&#xff0c;但本质完全不同。它们的主要区别体现在原子性保证和功能上&#xff1a; &#x1f50d; 核心区别对比表 特性volatile IntegerAtomicInteger原子性❌ 不保证复合操作原子性✅ 保证所有操作的原子性自增操作…

一生一芯 PA2 RTFSC

从src/isa/riscv32/inst.c出发。 向上搜索&#xff0c;理解宏定义的含义。 R(i) #define R(i) gpr(i) R(i)&#xff1a;访问第i号通用寄存器 会被替换为&#xff1a; #define gpr(idx) (cpu.gpr[check_reg_idx(idx)]) 分为两个部分&#xff1a; cpu.gprcheck_reg_idx c…

深度学习——手写数字识别

深度学习——手写数字识别 学习深度学习的朋友应该对MNIST数据集不陌生吧&#xff0c;相信很多人在刚开始学习深度学习的时候都会用到MNIST数据集进行书写数字识别。本篇文章参考鱼书创建一个深度网络来进行书写数字识别的任务。 如上图所示&#xff0c;这里使用的卷积层全都是…

HashMap算法高级应用实战:频率类子数组问题的5种破解模式

本文将深入剖析5种基于HashMap的高级模式&#xff0c;通过原理详解、多语言实现、性能对比和工业级应用&#xff0c;助您彻底掌握频率类子数组问题。 1. 深入解析&#xff1a;频率类子数组问题 1.1 问题定义与分类 频率类子数组问题是指需要统计或查找满足特定元素频率条件的…

【精选】计算机毕业设计HTML5智能宠物寻找与领养系统 跨平台宠物匹配 地图定位找宠 领养申请审核系统源码+论文+PPT+讲解

博主介绍&#xff1a; ✌我是阿龙&#xff0c;一名专注于Java技术领域的程序员&#xff0c;全网拥有10W粉丝。作为CSDN特邀作者、博客专家、新星计划导师&#xff0c;我在计算机毕业设计开发方面积累了丰富的经验。同时&#xff0c;我也是掘金、华为云、阿里云、InfoQ等平台…

拼多多商家端 anti_content 补环境分析

声明 本文章中所有内容仅供学习交流使用&#xff0c;不用于其他任何目的&#xff0c;抓包内容、敏感网址、数据接口等均已做脱敏处理&#xff0c;严禁用于商业用途和非法用途&#xff0c;否则由此产生的一切后果均与作者无关&#xff01; 部分python代码 import execjs impor…

电脑、手机长时间不关机可以吗

电脑和手机常年处于开机状态&#xff0c;只有在没电或者系统提示更新的时候才会关机。那问题来了&#xff0c;电脑、手机长时间不关机到底可不可以呢&#xff1f;今天咱们就来好好唠唠。 手机长时间不关机的情况 先来说说手机。现在的智能手机功能越来越强大&#xff0c;我们…

「AI大数据」| 《华为:面向智能制造的工业大模型标准化研究报告》

今天给大家介绍 《华为:面向智能制造的工业大模型标准化研究报告》&#xff0c;这是一份由中国电子技术标准化研究院联合华为等多家企业编写的权威报告&#xff0c;聚焦工业大模型在智能制造领域的标准化发展。报告详细分析了工业大模型的技术架构、应用场景、标准化现状与挑战…

Dinky1.2.3基于Kubernetes Application模式提交Flink作业

前言 Dinky 是一个开箱即用、易扩展&#xff0c;以 Apache Flink 为基础&#xff0c;连接 OLAP 和数据湖等众多框架的一站式实时计算平台&#xff0c;致力于流批一体和湖仓一体的探索与实践。 致力于简化Flink任务开发&#xff0c;提升Flink任务运维能力&#xff0c;降低Flink…

【软考高级架构设计师】——2025年上半年软考真题(回忆版)

目录 一、综合知识1.1、计算机基础与操作系统(15道单选)1.2、软件工程与架构(16道单选)1.3、数据与网络(8道单选)1.4、数学与逻辑(4道单选)1.5、其他(27道单选)1.6、英文题(质量属性)(5道单选)二、案例分析2.1、大模型训练系统(必选题)2.2、医院知识图谱(可选…

哈夫曼树Python实现

哈夫曼树构建原则&#xff1a; .统计频率&#xff1a;对待编码字符&#xff08;或数据块&#xff09;的频率进行统计。.初始化森林&#xff1a;将每个字符视为一棵只有根节点的二叉树&#xff0c;权值为频率。.合并树&#xff1a;重复以下操作&#xff0c;直到只剩一棵树&…

Dockerfile的学习与实践

Dockerfile通过一系列的命令和参数&#xff0c;构建自定义镜像。一般步骤如下&#xff1a; 一. 常用命令说明 基础命令具体命令描述例子FROMFROM[基础镜像:版本号]基于指定的基础镜像构建自定义镜像FROM eclipse-temurin:17-jdk-alpineRUNRUN构建容器需要运行的命令&#xff0…

【三大前端语言之一】静态网页语言:HTML详解

你知道你在浏览器中所看到的每一个按钮&#xff0c;每一个框&#xff0c;都是怎么创造出来的吗&#xff1f;它们并非魔法&#xff0c;而是由一种被称为HTML的语言精心构建的骨架。作为前端世界的三大基石之一&#xff08;HTML、CSS、JavaScript&#xff09;&#xff0c;HTML是万…

04、谁发明了深度学习的方法,是怎么发明的?

深度学习的发展是多位研究者长期探索的结果,其核心方法的形成并非由单一人物 “发明”,而是历经数十年理论积累与技术突破的产物。以下从关键人物、核心技术突破及历史背景三个维度,梳理深度学习方法的起源与发展脉络: 一、深度学习的奠基者与关键贡献者 1. Geoffrey Hin…

Jmeter ServerAgent在arm环境启动报错no libsigar-aarch64-linux.so in java.library.path

使用Jmeter压测的时候&#xff0c;用ServerAgent监测arm服务器的性能指标&#xff0c;在启动ServerAgent时&#xff0c;报错了&#xff1a;no libsigar-aarch64-linux.so in java.library.path 解决方案&#xff1a; 下载libsigar-aarch64-linux.so文件&#xff0c;放置在Serv…