【设计模式】结构型-组合模式

前言

在软件开发中,设计模式是一种被广泛应用的解决问题的方法论。其中,结构性设计模式是一类特别重要的模式,它们用于处理类或对象之间的组合关系,其中之一就是组合模式。组合模式允许客户端统一对待单个对象和对象的组合,从而简化了代码的复杂性,增强了代码的灵活性和可维护性。

一、 处理树形结构的挑战

场景假设:我们需要开发一个文件系统。它包含文件和文件夹,文件夹中又可以包含其他文件或文件夹。

// 文件类
class File {
    String name;
    
    File(String name) {
        this.name = name;
    }
    
    void display() {
        System.out.println("File: " + name);
    }
}

// 文件夹类,可以包含文件和其他文件夹
class Folder {
    String name;
    List<File> files;
    List<Folder> folders;
    
    Folder(String name) {
        this.name = name;
        this.files = new ArrayList<>();
        this.folders = new ArrayList<>();
    }
    
    void addFile(File file) {
        files.add(file);
    }
    
    void addFolder(Folder folder) {
        folders.add(folder);
    }
    
    void displayContents() {
        System.out.println("Folder: " + name);
        for (File file : files) {
            file.display();
        }
        for (Folder folder : folders) {
            folder.displayContents();
        }
    }
}

public class Main {
    public static void main(String[] args) {
        File file1 = new File("file1.txt");
        File file2 = new File("file2.txt");
        Folder folder1 = new Folder("folder1");
        Folder folder2 = new Folder("folder2");
        
        folder1.addFile(file1);
        folder2.addFile(file2);
        folder2.addFolder(folder1);
        
        // 显示文件夹 2 的内容,它包含文件夹 1 和文件 2
        folder2.displayContents();
        
        // 这个设计不利于扩展,如果我们想要添加新类型的文件系统元素,比如链接,我们需要修改 Folder 类
        // 这违反了开闭原则,并且使得代码难以维护和扩展
    }
}

上面的示例中,我们创建了两个类:File 和 Folder。File 类代表文件系统中的文件,而 Folder 类代表可以包含文件和其他文件夹的文件夹。这种设计的问题在于它不够灵活,难以扩展。例如,如果我们想要添加一个新的文件系统元素,如链接,我们需要修改 Folder 类来支持这种新类型的元素。这违反了开闭原则,即软件实体应该对扩展开放,对修改关闭。

除了上述问题,还存在以下问题:

  1. 代码重复:我们需要为文件和文件夹编写不同的处理代码,这导致了代码重复。
  2. 难以维护:如果文件系统的结构发生变化,比如添加新类型的元素,我们需要修改现有的代码,这使得维护变得困难。
  3. 扩展性差:当前的设计不允许灵活地添加新类型的文件系统元素,限制了系统的扩展性。

二、组合模式

组合模式是一种结构型设计模式,旨在将对象组合成树形结构以表示“部分-整体”的层次结构。这种模式用于将对象组织成树形结构,以表示“部分-整体”的层次关系,使得客户端可以统一处理单个对象和对象的组合。

在组合模式中,有两种主要类型的对象:

  1. 叶子节点(Leaf):表示树中的最终节点,它没有子节点。
  2. 复合节点(Composite):表示树中的分支节点,它可以包含其他子节点,即可以是叶子节点,也可以是复合节点。

三、组合模式的核心组成

组合模式由三个关键角色组成:

  1. 组件(Component):是组合中所有对象的共同接口,客户端通过这个接口操作组合中的对象。
  2. 叶子(Leaf):表示树中的叶子节点,它实现了组件接口。
  3. 复合(Composite):表示树中的复合节点,它实现了组件接口,并拥有子组件。

在这里插入图片描述

这里,Component 是抽象基类,定义了操作、添加子节点、删除子节点以及获取子节点的抽象方法。Leaf 类表示树结构中的叶子节点,它没有子节点。Composite 类表示树结构中的复合节点,它可以包含子节点,并且实现了对子节点的操作方法。

四、运用组合模式

场景假设: 我们一个文件系统,其中包含文件和文件夹。这个文件系统需要能够以统一的方式处理单个文件和包含多个文件或子文件夹的文件夹。

  1. 定义抽象构件(Component): 首先,我们创建一个抽象类或接口 FileSystemComponent,它包含了管理子部件的公共接口,如添加(add)、删除(remove)和显示结构(displayStructure)子部件。

    // 抽象构件:定义了文件系统中所有对象共有的接口
    public abstract class FileSystemComponent {
        protected String name;
        // 子部件列表,用于存储文件或文件夹
        protected List<FileSystemComponent> children;
    
        // 构造函数初始化文件系统组件的名称
        public FileSystemComponent(String name) {
            this.name = name;
            this.children = new ArrayList<>();
        }
    
        // 添加子部件的方法
        public abstract void add(FileSystemComponent component);
        // 移除子部件的方法
        public abstract void remove(FileSystemComponent component);
        // 显示结构的方法,用于输出组件结构
        public abstract void displayStructure();
    }
    
  2. 创建叶子构件(Leaf): 然后,我们实现 FileSystemComponent 接口来创建 File 类,这是树形结构中的末端对象,没有子部件。

    // 叶子构件:实现了抽象构件的操作,代表没有子部件的文件
    public class File extends FileSystemComponent {
        // 文件构造函数
        public File(String name) {
            super(name);
        }
    
        // 文件不支持添加操作,因此抛出异常
        @Override
        public void add(FileSystemComponent component) {
            throw new UnsupportedOperationException("Cannot add to a file.");
        }
    
        // 文件不支持移除操作,因此抛出异常
        @Override
        public void remove(FileSystemComponent component) {
            throw new UnsupportedOperationException("Cannot remove from a file.");
        }
    
        // 显示文件名称
        @Override
        public void displayStructure() {
            System.out.println("File: " + name);
        }
    }
    
  3. 创建容器构件(Composite): 接下来,我们创建 Folder 类,它也是 FileSystemComponent 的实现,可以包含叶子构件或其他容器构件。

    // 容器构件:可以包含叶子构件或其他容器构件的文件夹
    public class Folder extends FileSystemComponent {
        // 文件夹构造函数
        public Folder(String name) {
            super(name);
        }
    
        // 添加子部件到文件夹
        @Override
        public void add(FileSystemComponent component) {
            children.add(component);
        }
    
        // 从文件夹移除子部件
        @Override
        public void remove(FileSystemComponent component) {
            children.remove(component);
        }
    
        // 显示文件夹及其子部件的结构
        @Override
        public void displayStructure() {
            System.out.println("Folder: " + name);
            for (FileSystemComponent component : children) {
                component.displayStructure();
            }
        }
    }
    
  4. 客户端使用: 最后,客户端代码可以统一对待单个对象和组合对象,使得用户对单个对象和组合对象的使用具有一致性。

    // 客户端使用示例
    public class FileSystemClient {
        public static void main(String[] args) {
            // 创建文件
            File file1 = new File("file1.txt");
            File file2 = new File("file2.txt");
            // 创建文件夹,并添加文件
            Folder folder1 = new Folder("folder1");
            Folder folder2 = new Folder("folder2");
    
            folder1.add(file1);
            folder2.add(file2);
            folder2.add(folder1);
    
            // 显示文件夹 2 的内容,它包含文件夹 1 和文件 2
            folder2.displayStructure();
        }
    }
    

通过上述的组合模式,我们可以实现:

  1. 统一接口:File 和 Folder 都实现了 FileSystemComponent 接口,这意味着客户端代码可以以相同的方式处理它们。
  2. 递归结构:Folder 可以包含其他 Folder 对象,这允许我们创建一个递归的树形结构,反映了文件系统的真实层次结构。
  3. 易于扩展:如果我们想要添加新类型的文件系统元素,我们只需要创建一个新的类,继承自 FileSystemComponent,并实现必要的方法。我们不需要修改现有的 Folder 类。

五、组合模式的应用场景

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

  1. 图形用户界面(GUI)库: GUI 库通常使用组合模式来构建用户界面元素的层次结构。例如,窗口、面板、按钮和文本框可以作为容器对象,而文本、图像和复选框等用户界面元素可以作为叶子对象。
  2. 文件系统: 文件系统中的文件和目录可以被组织成一个树形结构。组合模式可以用于表示文件系统中的文件和目录,并且允许对它们进行统一的操作,如复制、移动和删除等。
  3. 组织架构: 组织架构中的部门、小组和员工等可以被组织成一个层次结构。组合模式可以用于表示组织架构,并且允许对不同层次的组织单元进行统一的管理。
  4. 菜单系统: 菜单系统通常具有多层次的菜单结构,例如菜单、子菜单和菜单项等。组合模式可以用于构建菜单系统,并且允许对菜单项和子菜单等组件进行统一的操作。
  5. 文件解析:在文件解析过程中,如 XML 文件、JSON 文件等,组合模式可以用来处理这些不同类型的文件,将它们表示为统一的对象,并提供一致的方法来读取和操作文件的内容。
  6. 电子设备: 电子设备通常具有复杂的层次结构,例如计算机系统中的硬件组件和软件模块等。组合模式可以用于表示这些层次结构,并且允许对不同层次的组件进行统一的控制和管理。

六、小结

组合模式是一种强大的设计模式,它提供了一种简单而灵活的方式来处理部分-整体层次关系。通过统一的接口和灵活的结构,组合模式使得系统更易于理解、扩展和维护。

推荐阅读

  1. Spring 三级缓存
  2. 深入了解 MyBatis 插件:定制化你的持久层框架
  3. Zookeeper 注册中心:单机部署
  4. 【JavaScript】探索 JavaScript 中的解构赋值
  5. 深入理解 JavaScript 中的 Promise、async 和 await

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

新手小白怎么学习接口自动化测试?

接口自动化测试是一种重要的测试技术&#xff0c;对于新手小白来说&#xff0c;学习这个技术需要一定的时间和耐心。在本文中&#xff0c;我将从零开始&#xff0c;详细而规范地介绍如何学习接口自动化测试。 1. 接口自动化测试的基础知识 在开始学习接口自动化测试之前&…

【教学类-13-05】20240604《数字色块图-5*7*8-A4横板-横切》中4班

背景需求&#xff1a; 【教学类-13-04】20230404《数字色块图判断密码是否正确-5*7*8-A4横板-横切》&#xff08;中班主题《我爱我家》)_图案密码色块-CSDN博客文章浏览阅读530次。【教学类-13-04】20230404《数字色块图判断密码是否正确-5*7*8-A4横板-横切》&#xff08;中班主…

270 基于matlab的模糊自适应PID控制

基于matlab的模糊自适应PID控制&#xff0c;具有10页报告。传统PID在对象变化时&#xff0c;控制器的参数难以自动调整。将模糊控制与PID控制结合&#xff0c;利用模糊推理方法实现对PID参数的在线自整定。使控制器具有较好的自适应性。使用MATLAB对系统进行仿真&#xff0c;结…

Python采集数据处理:利用Pandas进行组排序和筛选

概述 在现代数据处理和分析中&#xff0c;网络爬虫技术变得越来越重要。通过网络爬虫&#xff0c;我们可以自动化地从网页上收集大量的数据。然而&#xff0c;如何高效地处理和筛选这些数据是一个关键问题。本文将介绍如何使用Python的Pandas库对采集到的数据进行组排序和筛选…

安徽某高校数据挖掘作业4-5 (与一些碎碎念)

1. 编写程序求函数、、的极限。 解答&#xff1a; import sympy as sp# 定义符号变量 x x sp.symbols(x)# 定义函数 f1 sp.sin(20 * x) / x f2 (1 4 * x)**(2 / x) f3 (1 4 / x)**(2 * x)# 计算极限 limit1 sp.limit(f1, x, 0) limit2 sp.limit(f2, x, 0) limit3 sp…

测绘GIS和遥感领域比较好的公众号有哪些

测绘GIS和遥感领域&#xff0c;微信公众号作为信息传播和知识分享的重要渠道&#xff0c;为从业者提供了一个快速获取行业动态、技术进展和职业发展机会的平台。分享一些在测绘GIS和遥感领域表现突出的公众号推荐&#xff1a; 1. 慧天地&#xff1a;慧天地是一个知名的测绘公众…

倪师哲学。把智慧和时间都用在学习知识上

大家好&#xff0c;今天我们接着聊倪海厦老师的思想&#xff0c;一共整理出来了6点&#xff0c;之前4点已经讲过&#xff0c;今天我们讲第五点&#xff0c;这个呢也是倪老师的原话&#xff0c;不要浪费时间去做无谓的事情&#xff0c;把智慧和时间都用在学习知识上面。 其实啊现…

每天坚持写java锻炼能力---第一天(6.4)

今天的目标是菜单&#xff1a; B站/马士兵的项目菜单 package java1;import java.util.Scanner;public class Test {public static void main(String[] args) {while(true){ //3.加入死循环&#xff0c;让输入一直有System.out.println();System.out.println("--->项…

冯喜运:6.5黄金原油今日行情趋势分析及操作策略

【黄金消息面分析】&#xff1a;在全球经济的波动中&#xff0c;美元和黄金市场的表现一直是投资者关注的焦点。最近&#xff0c;市场情绪和经济数据的波动对这两个市场产生了显著的影响。周二欧市早盘&#xff0c;现货黄金价格出现短线回调&#xff0c;金价跌破2340美元/盎司&…

Pycharm创建Conda虚拟环境时显示CondaHTTPErOT

原因&#xff1a;conda源出问题了&#xff0c;之前可以用&#xff0c;现在报错。 最好的解决方案&#xff1a;找到conda源&#xff0c;换源即可。 步骤&#xff1a; 1.修改 .condarc 文件&#xff08;文件的位置在&#xff1a;C:\Users\(你的用户名)\.condarc&#xff09;&a…

.NET IoC 容器(三)Autofac

目录 .NET IoC 容器&#xff08;三&#xff09;AutofacAutofacNuget 安装实现DI定义接口定义实现类依赖注入 注入方式构造函数注入 | 属性注入 | 方法注入注入实现 接口注册重复注册指定参数注册 生命周期默认生命周期单例生命周期每个周期范围一个生命周期 依赖配置Nuget配置文…

AIGIS地图智能体功能预览——最强WebGIS打工人秒上岗

目录 前言1.这地图智能体是用来干什么的&#xff1f;2.智能体介绍3.二维效果4.三维效果5.大模型写不出来正确的代码怎么办&#xff1f;6.所以最终会产生一个什么样的现象&#xff1f;7.现在我们可用的大模型有哪些&#xff1f;8.不会写代码怎么开发自己的专属智能体&#xff1f…

处理无法拉取GitHub库的解决方案

提交和拉取github上的库总是失败&#xff0c;这里记录一下如何使用代理解决。 首先找到端口&#xff0c;记住它的端口 然后使用git命令 # HTTP/HTTPS 协议 git config ––global http.url.proxy http://127.0.0.1:port # 以 Github 为例 git config ––global http.https:/…

解决MyBatis的N+1问题

解决MyBatis的N1问题 N1问题通常出现在一对多关联查询中。当我们查询主表数据&#xff08;如订单&#xff09;并希望获取关联的从表数据&#xff08;如订单的商品&#xff09;时&#xff0c;如果每获取一条主表记录都要执行一次从表查询&#xff0c;就会产生N1次查询的问题。假…

线性电源运放驱动调整管的方案仿真

群里有人的电路板做出来电压不稳&#xff0c;加负载就掉电压。我对这个运放的工作状态不是很理解&#xff0c;所以仿真了一下。结果却是稳定的。他用12v给运放供电&#xff0c;要求输出10.5. 从仿真看。12运放供电只能输出9v。而且还是到了运放的极限。所以通过仿真后确定怀疑路…

10-Django项目--Ajax请求

目录 Ajax请求 简单示范 html 数据添加 py文件 html文件 demo_list.html Ajax_data.py 图例 Ajax请求 简单示范 html <input type"button" id"button-one" class"btn btn-success" value"点我"> ​ ​ <script>/…

实现秒传与限速!深度解析万亿GB网盘系统架构

1. 系统需求与挑战 1.1 DBox核心功能 在设计一个面向万亿GB的网盘系统时&#xff0c;我们需要首先明确系统的核心功能需求。DBox 作为一个高并发、高可靠的网盘系统&#xff0c;核心功能需求主要包括以下几点&#xff1a; 海量存储&#xff1a;支持存储海量数据&#xff0c;…

面粉厂/木材厂选择防爆客流统计系统的原因

在面粉厂和木材厂这样的特殊行业中&#xff0c;存在着一系列的痛点问题。 对于面粉厂而言&#xff0c;面粉粉尘的存在使其面临着爆炸的潜在危险&#xff0c;而人员的随意流动和不确切统计可能会进一步加剧安全风险。同时&#xff0c;难以精确掌握不同区域的人员分布情况&#x…

SploitScan:一款多功能实用型安全漏洞管理平台

关于SploitScan SploitScan是一款功能完善的实用型网络安全漏洞管理工具&#xff0c;该工具提供了用户友好的界面&#xff0c;旨在简化广大研究人员识别已知安全漏洞的相关信息和复现过程。 SploitScan可以帮助网络安全专业人员快速识别和测试已知安全漏洞&#xff0c;如果你需…

解线性方程组——最速下降法及图形化表示 | 北太天元 or matlab

文章所对应的视频讲解 最速下降法 解线性方程组 一、思路转变 A为对称正定矩阵&#xff0c; A x b Ax b Axb 求解向量 x x x这个问题可以转化为一个求 f ( x ) f(x) f(x)极小值点的问题&#xff0c;为什么可以这样&#xff1a; f ( x ) 1 2 x T A x − x T b c f(x) \f…