当前位置: 首页 > news >正文

复合设计模式

复合设计模式

复合设计模式是一种结构模式,可让您统一处理单个对象和对象的组合。

它允许您构建树状结构(例如,文件系统、UI 层次结构、组织结构),客户端可以使用同一界面处理单个元素和元素组。

它在以下情况下特别有用:
您需要表示部分-整体层次结构。

您希望 以一致的方式对叶节点和复合节点执行作。
您希望避免编写特殊情况逻辑来区分“单个”和“分组”对象。

在设计此类系统时,开发人员通常从 块或类型检查开始,以不同于集合的方式处理单个项目。例如, 在决定执行什么作之前,方法可能必须检查元素是按钮、面板还是容器。if-elserender()

但是,随着结构的复杂性增加,这种方法变得难以扩展,违反了开放/关闭原则,并在客户端代码和结构的内部组合之间引入了紧密耦合。

复合图案通过为所有元素定义一个通用接口来解决这个问题,无论它们是叶子还是复合元素。然后可以以相同的方式处理每个组件——允许客户端像简单对象一样对复杂的结构进行作。

让我们通过一个真实世界的示例,看看如何应用复合模式来建模一个既干净又可扩展的灵活分层系统。

问题:对文件资源管理器进行建模
想象一下,您正在构建一个文件资源管理器应用程序(例如 macOS 上的 Finder 或 Windows 上的文件资源管理器)。系统需要表示:

文件 – 具有名称和大小的简单项目。
文件夹 – 可以保存文件 和其他文件夹(甚至嵌套文件夹)的容器。

您的目标是支持以下作:
getSize()– 返回文件或文件夹的总大小(这是所有内容的总和)。
printStructure()– 打印项目的名称,包括缩进以显示层次结构。
delete()– 删除文件或文件夹及其中的所有内容。

天真的方法
一个简单的解决方案可能涉及两个单独的类: 和 。这是一个简化版本:FileFolder

文件

   class File {private String name;private int size;public int getSize() {return size;}public void printStructure(String indent) {System.out.println(indent + name);}public void delete() {System.out.println("Deleting file: " + name);}
}

文件夹

   import java.util.ArrayList;
import java.util.List;class Folder {private String name;private List<Object> contents = new ArrayList<>();public int getSize() {int total = 0;for (Object item : contents) {if (item instanceof File) {total += ((File) item).getSize();} else if (item instanceof Folder) {total += ((Folder) item).getSize();}}return total;}public void printStructure(String indent) {System.out.println(indent + name + "/");for (Object item : contents) {if (item instanceof File) {((File) item).printStructure(indent + "  ");} else if (item instanceof Folder) {((Folder) item).printStructure(indent + "  ");}}}public void delete() {for (Object item : contents) {if (item instanceof File) {((File) item).delete();} else if (item instanceof Folder) {((Folder) item).delete();}}System.out.println("Deleting folder: " + name);}

这种方法有什么问题?
随着结构变得越来越复杂,该解决方案引入了几个关键问题:

  1. 1. 重复类型检查
    像 、 和 这样的作 需要重复 检查和向下转换——导致逻辑重复和脆弱。getSize()printStructure()delete()instanceof
  2. 2. 没有共享抽象
    和 没有通用接口,这意味着您不能统一对待它们。你不能编写这样的代码:FileFolder
   List<FileSystemItem> items = List.of(file, folder);
for (FileSystemItem item : items) {item.delete();
}
  1. 3. 违反开放/关闭原则
    要添加新的项目类型(例如 , ),您必须修改发生类型检查的每个位置的现有逻辑,这会增加错误和回归的风险。ShortcutCompressedFolder
  2. 4. 缺乏递归优雅
    删除深度嵌套的文件夹或跨多个级别计算大小会变成嵌套条件和递归检查的混乱。

我们真正需要什么
我们需要一个解决方案:

为所有组件引入通用接口(例如,)。FileSystemItem
允许 通过多态性统一处理文件和文件夹。
使文件夹能够包含同一接口的列表,支持任意嵌套。
支持递归作,如 delete 和 getSize,无需类型检查。

使系统易于扩展 — 无需修改现有逻辑即可添加新的项目类型。
这正是复合设计模式所针对的问题。

复合模式
复合设计模式是一种结构设计模式,可让您以统一的方式处理单个对象和对象组。

在复合结构中,层次结构中的每个节点共享相同的接口,无论是叶子(例如 a )还是复合节点(例如 a )。这允许客户端在 两者之间递归一致地执行 、 或 等作。FileFoldergetSize()delete()render()

类图

组件接口(例如: 声明所有具体组件的通用接口)FileSystemItem
叶子(例如): 表示最终对象(无子对象)File
复合(例如): 表示可以容纳子项(包括其他复合)的对象Folder
客户端(例如): 使用共享界面处理组件FileExplorerApp

实现复合
我们将首先为文件系统中的所有项目定义一个通用接口,允许统一处理文件和文件夹。

  1. 1. 定义组件接口
   public interface FileSystemItem {int getSize();void printStructure(String indent);void delete();
}

此接口可确保所有文件系统项(无论是文件还是文件夹)向客户端公开相同的行为。

  1. 2. 创建 Leaf 类 –File
  public class File implements FileSystemItem {private final String name;private final int size;public File(String name, int size) {this.name = name;this.size = size;}@Overridepublic int getSize() {return size;}@Overridepublic void printStructure(String indent) {System.out.println(indent + "- " + name + " (" + size + " KB)");}@Overridepublic void delete() {System.out.println("Deleting file: " + name);}
}

每个 都是叶节点。它不包含任何子项。File

  1. 3. 创建复合类 –Folder
  import java.util.ArrayList;
import java.util.List;public class Folder implements FileSystemItem {private final String name;private final List<FileSystemItem> children = new ArrayList<>();public Folder(String name) {this.name = name;}public void addItem(FileSystemItem item) {children.add(item);}@Overridepublic int getSize() {int total = 0;for (FileSystemItem item : children) {total += item.getSize();}return total;}@Overridepublic void printStructure(String indent) {System.out.println(indent + "+ " + name + "/");for (FileSystemItem item : children) {item.printStructure(indent + "  ");}}@Overridepublic void delete() {for (FileSystemItem item : children) {item.delete();}System.out.println("Deleting folder: " + name);}
}

该 类是复合类。它可以同时包含 和 实例,使其具有递归性和可扩展性。FolderFileFolder

  1. 4. 客户端代码
  public class FileExplorerApp {public static void main(String[] args) {FileSystemItem file1 = new File("readme.txt", 5);FileSystemItem file2 = new File("photo.jpg", 1500);FileSystemItem file3 = new File("data.csv", 300);Folder documents = new Folder("Documents");documents.addItem(file1);documents.addItem(file3);Folder pictures = new Folder("Pictures");pictures.addItem(file2);Folder home = new Folder("Home");home.addItem(documents);home.addItem(pictures);System.out.println("---- File Structure ----");home.printStructure("");System.out.println("\nTotal Size: " + home.getSize() + " KB");System.out.println("\n---- Deleting All ----");home.delete();}
}

输出

---- File Structure ----
+ Home/
+ Documents/- readme.txt (5 KB)- data.csv (300 KB)
+ Pictures/- photo.jpg (1500 KB)Total Size: 1805 KB---- Deleting All ----
Deleting file: readme.txt
Deleting file: data.csv
Deleting folder: Documents
Deleting file: photo.jpg
Deleting folder: Pictures
Deleting folder: Home

使用复合模式,我们按照文件系统的自然工作方式对文件系统进行了建模,将其建模为项目树,其中一些是叶子,另一些是容器。每个作 (, , ) 现在都是模块化的、递归的和可扩展的。getSize()printStructure()delete()

我们通过复合材料取得了什么成就?
统一处理:文件和文件夹共享一个通用界面,允许多态性

干净递归:不,没有铸造——只是委托instanceof

可扩展性:轻松支持深度嵌套结构

可维护性:添加新文件类型(例如,Shortcut、CompressedFolder)很容易

可扩展性:可以通过接口扩展或访问者模式添加新作

其他阅读材料:

https://pan.baidu.com/s/1c1oQItiA7nZxz8Rnl3STpw?pwd=yftc
https://pan.quark.cn/s/dec9e4868381

http://www.dtcms.com/a/344486.html

相关文章:

  • 阿里云详解:与 AWS、GCP 的全方位比较
  • openEuler系统中home文件夹下huawei、HwHiAiUser、lost+found 文件夹的区别和作用
  • 农业-学习记录
  • vue中监听页面滚动位置
  • Playwright进阶指南 (5):拦截与模拟网络请求
  • 【LLMs篇】19:vLLM推理中的KV Cache技术全解析
  • SymPy 中抽象函数的推导与具体函数代入
  • 《器件在EMC中的应用》---磁珠在EMC中的应用
  • 一次性密码(OTP)原理及应用
  • 解决 PyTorch 导入错误:undefined symbol: iJIT_NotifyEvent
  • 数据结构之深入探索快速排序
  • Spring Start Here 读书笔记:第10章 Implementing REST services
  • vue vxe-gantt 甘特图自定义任务条样式模板 table 自定义插槽模板
  • 云手机是依靠哪些技术运行的?
  • Shell脚本源码安装Redis、MySQL、Mongodb、PostgreSQL(无报错版)
  • 遥感机器学习入门实战教程|Sklearn案例⑥:网格搜索与超参数优化
  • Logstash——性能、可靠性与扩展性架构
  • Python爬虫实战:构建古籍抄本数据采集分析系统
  • 实验二 Cisco IOS Site-to-Site Pre-share Key
  • LeetCode第55题 - 跳跃游戏
  • GitHub 热榜项目 - 日榜(2025-08-22)
  • 解析三品汽车零部件PLM系统解决方案:如何助力行业解决研发管理难题
  • Curity CTO 深度解析:AI 智能体正让我们“梦游”般陷入安全危机
  • 车载中控:汽车的数字大脑与交互核心
  • 第五章:Leaflet 进阶:高德地图交互与事件处理全解析
  • git回滚相关命令指南
  • 机器学习概述:从零开始理解人工智能的核心技术
  • 树莓派安装pyqt5 opencv等库一些问题
  • 力扣面试150(63/150)
  • C++显示类型转换运算符static_cast使用指南