组合模式(Composite Pattern):树形结构的优雅处理方案

目录

  • 1. 什么是组合模式
  • 2. 组合模式的结构
  • 3. UML类图
  • 4. 代码实现
  • 5. 常见应用场景
  • 6. 优缺点分析
  • 7. 最佳实践建议

1. 什么是组合模式

组合模式(Composite Pattern)是一种结构型设计模式,它允许你将对象组合成树形结构来表现"整体-部分"的层次关系。使用组合模式后,客户端可以统一对待单个对象和组合对象,无需关心处理的是一个叶子节点还是一个组合节点。

这种模式特别适合处理那些需要树形结构来展示的场景,比如:

  • 文件系统的目录结构
  • 公司的组织架构
  • GUI界面的控件层次
  • 菜单系统的多级菜单

2. 组合模式的结构

组合模式主要包含以下几个角色:

  1. Component(抽象组件):定义组合对象和叶子对象的共同接口
  2. Leaf(叶子节点):表示组合中的叶子节点对象没有子节点
  3. Composite(组合节点):表示组合中的分支节点对象,可以包含子节点

3. UML类图

«abstract»
Component
+operation()
+add(Component)
+remove(Component)
+getChild(int)
Leaf
+operation()
Composite
-children: List
+operation()
+add(Component)
+remove(Component)
+getChild(int)
  1. Component(抽象组件)
    • 这是整个组合模式的核心,定义了叶子和组合对象的共同接口
    • operation():声明实际业务方法
    • add()/remove()/getChild():定义管理子组件的方法
    • 可以声明为抽象类或接口
  2. Leaf(叶子节点)
    • 表示叶子节点,继承自Component
    • 实现operation()方法
    • 没有子节点,因此add/remove/getChild方法可能为空实现或抛出异常
  3. Composite(组合节点)
    • 表示容器节点,继承自Component
    • 包含子组件集合(children)
    • 实现operation()方法,通常会递归调用子组件的operation
    • 实现add/remove/getChild等方法来管理子组件

4. 代码实现

让我们通过一个文件系统的例子来实现组合模式:

文件系统示例说明

在这个文件系统的例子中,我们模拟了真实文件系统的树形结构。这是一个典型的组合模式应用场景,因为:

  1. 文件和目录都是文件系统的组成部分
  2. 目录可以包含文件和子目录
  3. 用户可以以统一的方式处理文件和目录(如计算大小、显示结构等)

代码如下:

// 抽象组件:文件系统项
public abstract class FileSystemNode {protected String name;public FileSystemNode(String name) {this.name = name;}// 显示节点信息public abstract void display(String prefix);// 获取文件或目录大小public abstract long getSize();
}// 叶子节点:文件
public class File extends FileSystemNode {private long size; // 文件大小public File(String name, long size) {super(name);this.size = size;}@Overridepublic void display(String prefix) {System.out.println(prefix + "- " + name + " (" + size + " bytes)");}@Overridepublic long getSize() {return size;}
}// 组合节点:目录
public class Directory extends FileSystemNode {private List<FileSystemNode> children = new ArrayList<>();public Directory(String name) {super(name);}// 添加子节点public void add(FileSystemNode node) {children.add(node);}// 移除子节点public void remove(FileSystemNode node) {children.remove(node);}@Overridepublic void display(String prefix) {System.out.println(prefix + "+ " + name);// 递归显示子节点children.forEach(child -> child.display(prefix + " "));}@Overridepublic long getSize() {// 计算所有子节点的大小总和return children.stream().mapToLong(FileSystemNode::getSize).sum();}
}// 客户端使用示例
public class Client {public static void main(String[] args) {// 创建目录结构Directory root = new Directory("root");Directory home = new Directory("home");Directory user = new Directory("user");File file1 = new File("document.txt", 100);File file2 = new File("image.jpg", 2000);File file3 = new File("config.xml", 150);root.add(home);home.add(user);user.add(file1);user.add(file2);root.add(file3);// 显示目录结构root.display("");// 计算总大小System.out.println("Total size: " + root.getSize() + " bytes");}
}
FileSystemNode(Component)
  • 作为抽象组件,定义了文件系统中所有节点的共同接口
  • name属性:所有文件系统项都有名称
  • display():统一的显示方法,用于展示节点信息
  • getSize():统一的大小计算方法
  • 设计为抽象类而不是接口,因为可以共享name属性的实现
File(Leaf)
  • 代表组合模式中的叶子节点,表示文件系统中的文件
  • 实现了所有抽象方法,但不包含子节点
  • size属性:文件特有的属性,用于存储文件大小
  • display():直接显示文件信息
  • getSize():直接返回文件大小,无需递归计算
Directory(Composite)
  • 代表组合模式中的组合节点,表示文件系统中的目录
  • children:存储子节点的集合,可以包含文件和子目录
  • add()/remove():提供了管理子节点的方法
  • display():递归显示目录结构,体现了树形结构的遍历
  • getSize():通过递归计算所有子节点大小的总和

5. 常见应用场景

  1. 图形界面框架
    • 窗口包含面板
    • 面板包含按钮、文本框等控件
  2. 文件系统
    • 目录包含子目录和文件
    • 统一处理文件和目录的操作
  3. 组织架构
    • 公司部门层级关系
    • 员工和部门的统一管理
  4. 菜单系统
    • 多级菜单的实现
    • 菜单项和子菜单的统一处理

6. 优缺点分析

优点

  1. 简化客户端代码:客户端可以一致地处理组合对象和叶子对象
  2. 易于扩展:新增组合对象或叶子对象都很方便,不需要修改现有代码
  3. 具有较强的灵活性:可以通过组合创建复杂的树形结构

缺点

  1. 可能使设计变得过于一般化:为了使组件接口统一,可能需要在接口中声明一些不太适合叶子节点的方法
  2. 增加了系统复杂度:需要额外的抽象层和类型检查

7. 最佳实践建议

  1. 安全性与透明性的权衡
    • 安全方式:在Composite类中定义管理子节点的方法
    • 透明方式:在Component中定义所有方法
  2. 子组件管理
    • 考虑是否需要父节点引用
    • 决定由谁负责管理子组件的添加和删除
  3. 遍历方式
    • 可以实现迭代器模式来遍历组合结构
    • 考虑深度优先或广度优先遍历的需求
  4. 类型安全
    • 使用泛型来增强类型安全
    • 在必要时进行类型检查

示例:使用泛型改进的组合模式

public abstract class Component<T extends Component<T>> {
protected List<T> children = new ArrayList<>();
public void add(T component) {
children.add(component);
}
public void remove(T component) {
children.remove(component);
}
public abstract void operation();
}

总结

组合模式是一种优雅的设计模式,特别适合处理树形结构的问题。它通过统一对象的接口,简化了客户端的调用,使得代码更加优雅和易于维护。在实际应用中,需要根据具体场景来权衡是否使用组合模式,以及如何实现细节。

好的设计模式应该是解决问题的工具,而不是目标。在使用组合模式时,应该始终关注它是否真正简化了你的问题,而不是为了使用设计模式而使用设计模式。

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

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

相关文章

AI开源南京分享会回顾录

AI 开源南京分享会&#xff0c;已于2024年11月30日下午在国浩律师&#xff08;南京&#xff09;事务所5楼会议厅成功举办。此次活动由 KCC南京、PowerData、RISC-Verse 联合主办&#xff0c;国浩律师&#xff08;南京&#xff09;事务所协办。 活动以“开源视角的 AI 对话”为主…

OpenCV 图像变换与处理实战

OpenCV快速通关 第一章&#xff1a;OpenCV 简介与环境搭建 第二章&#xff1a;OpenCV 图像基本操作 第三章&#xff1a;OpenCV 图像变换与处理实战 OpenCV 图像变换与处理实战 OpenCV快速通关OpenCV 图像变换与处理实战一、OpenCV 基础与图像处理概览二、图像变换理论精析三、…

Ubuntu22.04安装docker desktop遇到的bug

1. 确认已启用 KVM 虚拟化 如果加载了模块&#xff0c;输出应该如下图。说明 Intel CPU 的 KVM 模块已开启。 否则在VMware开启宿主机虚拟化功能&#xff1a; 2. 下一步操作&#xff1a; Ubuntu | Docker Docs 3. 启动Docker桌面后发现账户登陆不上去&#xff1a; Sign in | …

【深度学习入门】深度学习介绍

1.1 深度学习介绍 学习目标 目标 知道深度学习与机器学习的区别了解神经网络的结构组成知道深度学习效果特点 应用 无 区别 特征提取方面 机器学习的特征工程步骤是要靠手动完成的&#xff0c;而且需要大量领域专业知识深度学习通常由多个层组成&#xff0c;它们通常将更简…

实现按键按下(低电平)检测到下降沿

按照流程进行编程 步骤1&#xff1a; 初始化函数 包括时基工作参数配置 输入通道配置 更新中断使能 使能捕获、捕获中断及计数器 HAL_TIM_IC_Init(&ic_handle) //时基参数配置 HAL_TIM_IC_ConfigChannel(&ic_handle,&ic_config,TIM_CHANNEL_2) //输…

【Linux金典面试题(上)】41道Linux金典面试问题+详细解答,包含基本操作、系统维护、网络配置、脚本编程等问题。

大家好&#xff0c;我是摇光~&#xff0c;用大白话讲解所有你难懂的知识点 之前写了一篇关于 python 的面试题&#xff0c;感觉大家都很需要&#xff0c;所以打算出一个面试专栏。 【数据分析岗】Python金典面试题 这个专栏主要针对面试大数据岗位、数据分析岗位、数据运维等…

【Ubuntu】使用ip link工具创建虚拟局域网并配置?

&#x1f98b;&#x1f98b;&#x1f98b;如何使用ip link工具创建虚拟局域网&#xff1f; sudo ip link add link enx888bd66b7000 name enx.120 type vlan id 120 上述命令使用ip link工具在Linux系统中创建了一个新的虚拟局域网&#xff08;VLAN&#xff09;接口&#xff0c…

汽车车牌标记支持YOLO,COCO,VOC三种格式标记,4000张图片的数据集

本数据集支持YOLO&#xff0c;COCO&#xff0c;VOC三种格式标记汽车车牌&#xff0c;无论是新能源汽车还是油车都能识别标记&#xff0c;该数据集一共包含4000张图片 数据集分割 4000总图像数 训练组 70&#xff05; 2800图片 有效集 20&#xff05; 800图片 测…

Docker 如何在容器未运行时修改内部配置文件

今天遇到一个数据库分组查询的问题&#xff1a;sql_modeonly_full_group_by&#xff0c;即查询 SQL 的字段列表中包含了未分组的字段&#xff0c;在 mysql7 版本下需要修改数据库的配置文件 my.cnf 中的 sql_mode&#xff0c;去除掉值中的 ONLY_FULL_GROUP_BY。 第一次进入 do…

游秦岭山感

巍乎高哉&#xff01; 悠悠大秦岭 佑吾华夏之根脉 八水润之 泽万物而赋予生机 于万山之山中 享自然之美于万物 西有昆仑祖龙脉 东有秦岭护关中 绿水青山国之本 万山长青谋发展 旭日东升耀中华 固我山河永泰安 你我同行共保护 关中龙脉更兴旺

阿里云-通义灵码:测试与实例展示

目录 一.引子 二.例子 三.优点 四.其他优点 五.总结 一.引子 在软件开发的广袤天地中&#xff0c;阿里云通义灵码宛如一座蕴藏无尽智慧的宝库&#xff0c;等待着开发者们去深入挖掘和探索。当我们跨越了入门的门槛&#xff0c;真正开始使用通义灵码进行代码生成和开发工作…

微信小程序中使用miniprogram-sm-crypto实现SM4加密攻略

在微信小程序开发过程中&#xff0c;数据安全至关重要。本文将为大家介绍如何在微信小程序中使用miniprogram-sm-crypto插件进行SM4加密&#xff0c;确保数据传输的安全性。 一、SM4加密简介 SM4是一种对称加密算法&#xff0c;由国家密码管理局发布&#xff0c;适用于商密领…

使用 Ansys Fluent 对气体泄漏检测进行建模

了解使用 Ansys Fluent 仿真气体泄漏和确保安全的前沿技术。 挑战 气体泄漏对人类安全和环境构成重大风险。及早检测气体泄漏可以防止潜在的灾难&#xff0c;包括爆炸、火灾和有毒物质暴露。有效的气体泄漏检测系统对于石油和天然气、化学加工和住宅基础设施等行业至关重要。…

原创 传奇996_55——后端如何点击npc隐藏主界面

点击图片退出&#xff0c;举例&#xff1a; |linkexit Img|ax0.5|ay0.5|percentx50|percenty50|imgpublic/touming2.png|hideMain1|linkexit <Img|x0|y0|esc1|show4|bg1|move0|imgcustom/new/longhun/bg.png|loadDelay0|reset1|hideMain1>

Golang学习笔记_01——包

文章目录 包&#xff08;package&#xff09;1. 定义2. 导入3. 初始化4. 可见性4. 注意4.1 包声明4.2 main包4.3 包的导入4.4标识符的可见性4.5 包的初始化4.6 避免命名冲突4.7 包的路径和名称4.8 匿名导入4.9 使用Go Modules 包&#xff08;package&#xff09; 在Golang&…

C# 中的委托与事件:实现灵活的回调机制

C#中的委托&#xff08;Delegate&#xff09;和事件&#xff08;Event&#xff09;。委托和事件是C#中非常重要的特性&#xff0c;它们允许你实现回调机制和发布-订阅模式&#xff0c;从而提高代码的灵活性和解耦程度。通过使用委托和事件&#xff0c;你可以编写更加模块化和可…

QT图形/视图架构详解(一)

场景、视图与图形项 图形/视图架构主要由 3 个部分组成&#xff0c;即场景、视图和图形项&#xff0c;三者的关系如图所示&#xff1a; 场景、视图和图形项的关系 场景&#xff08;QGraphicsScene 类&#xff09; 场景不是界面组件&#xff0c;它是不可见的。场景是一个抽象的…

c++三维移动射击

大家好&#xff0c;我是love-putter&#xff0c;距离上一篇文章的发布已经一年了&#xff0c;在这一年里&#xff0c;经过时间的沉淀&#xff0c;希望给大家带来更好的作品&#xff0c;废话不多说&#xff0c;上代码 #include <iostream> #include <ctime> #inclu…

LLM之RAG实战(五十)| FastAPI:构建基于LLM的WEB接口界面

FastAPI是WEB UI接口&#xff0c;随着LLM的蓬勃发展&#xff0c;FastAPI的生态也迎来了新的机遇。本文将围绕FastAPI、OpenAI的API以及FastCRUD&#xff0c;来创建一个个性化的电子邮件写作助手&#xff0c;以展示如何结合这些技术来构建强大的应用程序。 下面我们开始分步骤操…

Maven学习(Maven项目模块化。模块间“继承“机制。父(工程),子项目(模块)间聚合)

目录 一、Maven项目模块化&#xff1f; &#xff08;1&#xff09;基本介绍。 &#xff08;2&#xff09;汽车模块化生产再聚合组装。 &#xff08;3&#xff09;Maven项目模块化图解。 1、maven_parent。 2、maven_pojo。 3、maven_dao。 4、maven_service。 5、maven_web。 6…