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

news2025/6/6 11:59:00

说明:本文介绍结构型设计模式之一的组合模式

定义

组合模式(Composite Pattern)又叫作整体-部分(Part-Whole)模式,它的宗旨是通过将单个对象(叶子节点)和组合对象(树枝节点)用相同的接口进行表示,使得客户对单个对象和组合对象的使用具有一致性,属于结构型设计模式。(引自《设计模式就该这样学》P263)

文件系统

以文件系统为例,如下,是服务器上某个文件夹的文件结构,该文件夹下既有文件夹,也有文件

在这里插入图片描述

如果我要构建这样一个文件夹-文件系统,代码应该是这样写的,如下:

(图片文件,ImageFile)

/**
 * 图片文件
 */
public class ImageFile {

    /**
     * 图片名称
     */
    private String name;

    public ImageFile(String name) {
        this.name = name;
    }

    /**
     * 展示
     */
    public void show(int space) {
        for (int i = 0; i < space; i++) {
            System.out.print(" ");
        }
        System.out.println(name);
    }
}

(电影文件,MovieFile)

/**
 * 电影文件
 */
public class MovieFile {

    /**
     * 电影名称
     */
    private String name;

    public MovieFile(String name) {
        this.name = name;
    }

    /**
     * 展示
     */
    public void show(int space) {
        for (int i = 0; i < space; i++) {
            System.out.print(" ");
        }
        System.out.println(name);
    }
}

(文件夹,Folder,定义多个文件集合,并开放对应的增加方法)

import java.util.ArrayList;

/**
 * 文件夹
 */
public class Folder {
    /**
     * 文件夹名称
     */
    private String name;

    /**
     * 文件夹下的文件夹
     */
    private ArrayList<Folder> folders = new ArrayList<>();

    /**
     * 文件夹下的图片文件
     */
    private ArrayList<ImageFile> imageFiles = new ArrayList<>();

    /**
     * 文件夹下的视频文件
     */
    private ArrayList<MovieFile> movieFiles = new ArrayList<>();

    public Folder(String name) {
        this.name = name;
    }

    /**
     * 添加文件夹
     */
    public void addFolder(Folder folder) {
        folders.add(folder);
    }

    /**
     * 添加图片文件
     */
    public void addImageFile(ImageFile imageFile) {
        imageFiles.add(imageFile);
    }

    /**
     * 添加电影文件
     */
    public void addMoveFile(MovieFile movieFile) {
        movieFiles.add(movieFile);
    }

    /**
     * 展示
     */
    public void show(int space) {
        // 打印文件夹
        space++;
        for (int i = 0; i < space; i++) {
            System.out.print(" ");
        }
        System.out.println(name);
        for (Folder folder : folders) {
            folder.show(space);
        }

        // 打印图片文件
        space++;
        for (ImageFile imageFile : imageFiles) {
            imageFile.show(space);
        }

        // 打印电影文件
        space++;
        for (MovieFile movieFile : movieFiles) {
            movieFile.show(space);
        }
    }
}

(客户端使用,Client)

public class Client {
    public static void main(String[] args) {
        // 顶级文件夹
        Folder folder = new Folder("folder");

        // 二级文件夹
        Folder images = new Folder("images");
        Folder movies = new Folder("movies");

        // 三级目录下的文件
        ImageFile boy = new ImageFile("boy.png");
        ImageFile girl = new ImageFile("girl.png");
        images.addImageFile(boy);
        images.addImageFile(girl);

        // 三级文件夹
        Folder director1 = new Folder("heizeming");
        Folder director2 = new Folder("xiaolinzhengshu");

        // 四级目录
        MovieFile movieFile1 = new MovieFile("luoshengmen.mp4");
        MovieFile movieFile2 = new MovieFile("qiwushi.mp4");
        director1.addMoveFile(movieFile1);
        director1.addMoveFile(movieFile2);

        MovieFile movieFile3 = new MovieFile("duomingjian.mp4");
        MovieFile movieFile4 = new MovieFile("qiefu.mp4");
        director2.addMoveFile(movieFile3);
        director2.addMoveFile(movieFile4);
        movies.addFolder(director1);
        movies.addFolder(director2);

        // 文件夹添加到顶级文件夹
        folder.addFolder(images);
        folder.addFolder(movies);
        folder.show(0);
    }
}

运行,hora!(看!),能实现目的

在这里插入图片描述

但这里存在问题,文件系统,简单来说只有文件夹和文件两个实体对象,代码中的图片文件、电影文件可以抽象为文件(File),这是整体与个体的场景。

组合模式

使用组合模式改进上述代码,如下:

(抽象节点类,Node)

/**
 * 抽象节点
 */
public abstract class Node {

    /**
     * 节点名称
     */
    protected String name;

    public Node(String name) {
        this.name = name;
    }

    /**
     * 添加节点
     */
    protected abstract void add(Node node);

    /**
     * 展示
     */
    protected void show(int space) {
        for (int i = 0; i < space; i++) {
            System.out.print(" ");
        }
        System.out.println(name);
    }

    /**
     * 重载方法,使用的时候就不用给参数了
     */
    protected void show() {
        show(0);
    }
}

(文件夹,Folder)

import java.util.ArrayList;

/**
 * 文件夹
 */
public class Folder extends Node {

    /**
     * 文件夹下的子节点
     */
    private ArrayList<Node> childrenNodes = new ArrayList<>();

    /**
     * 调用父类的构造方法
     */
    public Folder(String name) {
        super(name);
    }

    @Override
    protected void add(Node node) {
        childrenNodes.add(node);
    }

    @Override
    protected void show(int space) {
        super.show(space);
        space++;
        for (Node node : childrenNodes) {
            node.show(space);
        }
    }
}

(文件,File)

/**
 * 文件
 */
public class File extends Node {

    /**
     * 调用父类的构造方法
     */
    public File(String name) {
        super(name);
    }

    @Override
    protected void add(Node node) {
        System.out.println("不能添加子节点");
    }

    @Override
    protected void show(int space) {
        super.show(space);
    }
}

(客户端使用,Client)

public class Client {
    public static void main(String[] args) {
        // 顶级文件夹
        Folder folder = new Folder("folder");

        // 二级文件夹
        Folder images = new Folder("images");
        Folder movies = new Folder("movies");

        // 三级目录下的文件
        File boy = new File("boy.png");
        File girl = new File("girl.png");
        images.add(boy);
        images.add(girl);

        // 三级文件夹
        Folder director1 = new Folder("heizeming");
        Folder director2 = new Folder("xiaolinzhengshu");

        // 四级目录
        File movieFile1 = new File("luoshengmen.mp4");
        File movieFile2 = new File("qiwushi.mp4");
        director1.add(movieFile1);
        director1.add(movieFile2);

        File movieFile3 = new File("duomingjian.mp4");
        File movieFile4 = new File("qiefu.mp4");
        director2.add(movieFile3);
        director2.add(movieFile4);
        movies.add(director1);
        movies.add(director2);

        // 文件夹添加到顶级文件夹
        folder.add(images);
        folder.add(movies);
        folder.show();
    }
}

执行如下,也实现了目的

在这里插入图片描述

这么看下来,文件系统场景使用组合模式实现是很不错的,代码少了很多,也削减了文件夹类中的职责(可以对比下Folder类前后的代码)

使用场景

在《设计模式就该这样学》(P229)这本书中,提到状态模式适用于以下场景:

(1)希望客户端可以忽略组合对象与单个对象的差异;

(2)对象层次具备整体和部分,呈树形结构;

除了文件系统、企业组织架构场景,我还没想到其他使用场景;

总结

本文介绍了结构型设计模式中的组合模式,参考《设计模式就该这样学》、《秒懂设计模式》、《设计模式的艺术》(第一版)这三本书,其中的例子来自《秒懂设计模式》。

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

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

相关文章

Unity Mac 笔记本操作入门

在 macOS 笔记本电脑上使用 Unity Editor 的场景视图 (Scene View) 旋转视角&#xff0c;主要依赖于触摸板手势和键盘修饰键的组合。由于没有物理中键&#xff0c;操作方式会与 Windows 鼠标略有不同。 以下是具体的旋转视角操作&#xff1a; 1. 基本旋转视角 (Orbit) 这是最…

实时数据仓库是什么?数据仓库设计怎么做?

目录 一、实时数据仓库是什么 &#xff08;一&#xff09;实时数据仓库的定义 &#xff08;二&#xff09;实时数据仓库的特点 二、实时数据仓库的应用场景 &#xff08;一&#xff09;金融行业 &#xff08;二&#xff09;电商行业 &#xff08;三&#xff09;物联网行…

Linux(12)——基础IO(下)

目录 六、重定向 &#x1f4c4;输出重定向 &#x1f4c4;输入重定向 &#x1f4c4;追加重定向 &#x1f4c4;dup2 七、理解一切皆文件 八、缓冲区 &#x1f9e0;什么是缓冲区 &#x1f9e0;为什么要引入缓冲区 &#x1f4c4;缓冲区类型 九、FILE 六、重定向 我们这…

WPF可拖拽ListView

1.控件描述 WPF实现一个ListView控件Item子项可删除也可拖拽排序&#xff0c;效果如下图所示 2.实现代码 配合 WrapPanel 实现水平自动换行&#xff0c;并开启拖拽 <ListViewx:Name"listView"Grid.Row"1"Width"300"AllowDrop"True&…

[蓝桥杯]倍数问题

倍数问题 题目描述 众所周知&#xff0c;小葱同学擅长计算&#xff0c;尤其擅长计算一个数是否是另外一个数的倍数。但小葱只擅长两个数的情况&#xff0c;当有很多个数之后就会比较苦恼。现在小葱给了你 nn 个数&#xff0c;希望你从这 nn 个数中找到三个数&#xff0c;使得…

【MySQL】 约束

一、约束的定义 MySQL 约束是用于限制表中数据的规则&#xff0c;确保数据的 准确性 和 一致性 。约束可以在创建表时定义&#xff0c;也可以在表创建后通过修改表结构添加。 二、常见的约束类型 2.1 NOT NULL 非空约束 加了非空约束的列不能为 NULL 值&#xff0c;如果可以…

前端vue打开多个窗口,关闭窗口后才继续执行后续逻辑

1.打开第一个弹窗 弹窗的按钮代码 2.点击窗口1中按钮&#xff0c;打开新的窗口 // 请领单按钮点击 async cb_6_delClick() {let ls_yfbm this.st_3Value.BMBMlet pstring {}pstring.a ls_yfbmpstring.b this.queryFormDialog.outDepotDeptCodeawait this.openwithparm_w_md…

「深度拆解」Spring Boot如何用DeepSeek重构MCP通信层?从线程模型到分布式推理的架构进化

什么是MCP&#xff1f; MCP&#xff08;Model Context Protocol&#xff0c;模型上下文协议&#xff09;是由Anthropic公司于2024年11月推出的开放标准协议&#xff0c;旨在为大型语言模型&#xff08;LLM&#xff09;与外部数据源、工具及系统提供统一的交互接口&#xff0c;被…

【西门子杯工业嵌入式-2-点亮一颗LED】

西门子杯工业嵌入式-2-点亮一颗LED 一、课程回顾与目标1.上节课内容回顾2.本节课目标 二、硬件连接与原理1. 硬件连接方式2. 连接实例 三、GPIO原理知识1. GPIO结构2. 推挽输出模式原理 四、软件实现步骤1. 项目结构设置2. 函数定义3. led.c 文件编写初始化函数 led_init交替闪…

代码随想录算法训练营第60期第五十五天打卡

大家好&#xff0c;我们今天继续我们图论的部分&#xff0c;其实我们昨天是主要讲解了深搜与广搜的理论基础&#xff0c;我们大体上了解了两种算法的差异与适用情景&#xff0c;今天我们就继续我们的图论的章节&#xff0c;以后几天的题目是图论中比较有名的问题叫做岛屿问题&a…

重磅更新! 基于Gemini 2.5 Pro打造的AI智能体PlantUML-X上线!

目录 图表绘制AI智能体PlantUML-X上线通过简单的提示词创建各种UML图&#xff1a;轻松搞定其它类型的技术图表&#xff1a; AI智能体PlantUML-X功能实测画一个在Java中的一个简单的用户登录功能的时序图效果展示&#xff1a;根据详细内容生成系统架构图效果展示&#xff1a;效果…

[5-02-04].第01节:Jmeter环境搭建:

JMeter笔记大纲 Jmeter依赖于JDK&#xff0c;所以必须确保当前计算机上已经安装了JDK&#xff0c;并且配置了环境变量 一、JMeter概述&#xff1a; 1.1.JMeter是什么&#xff1a; JMeter是Appache组织使用java开发的一款测试工具 可以用于对服务器、网络或对象模拟巨大的负载…

AI智能推荐实战之RunnableParallel并行链

导读&#xff1a;在现代AI应用开发中&#xff0c;如何高效处理多维度数据分析始终是开发者面临的核心挑战。当您需要同时进行情感分析、关键词提取和实体识别&#xff0c;或者要对比多个AI模型的输出结果时&#xff0c;传统的串行处理方式往往效率低下。 本文将深入解析LangCha…

Gemini开源项目DeepResearch:基于LangGraph的智能研究代理技术原理与实现

引言 在人工智能快速发展的今天&#xff0c;如何构建一个能够进行深度研究、自主学习和迭代优化的AI系统成为了技术前沿的重要课题。Gemini开源的DeepResearch一周收获7.9k Star&#xff0c;Google的开源项目Gemini DeepResearch技术通过结合LangGraph框架和Gemini大语言模型&…

Doris Catalog 联邦分析查询性能优化:从排查到优化的完整指南

在大数据分析中&#xff0c;Doris 的 Catalog 联邦分析功能为整合多源数据提供了有力支持。然而&#xff0c;在实际应用中&#xff0c;可能会遇到各种问题影响其正常运行。本文将详细剖析这些问题并提供解决方案。 一、联邦分析查询慢&#xff1a;内外表通用排查逻辑 当遇到 …

01 Deep learning神经网络的编程基础 二分类--吴恩达

二分类 1. 核心定义 二分类任务是监督学习中最基础的问题类型&#xff0c;其目标是将样本划分为两个互斥类别。设样本特征空间为 X ⊆ R n \mathcal{X} \subseteq \mathbb{R}^n X⊆Rn&#xff0c;输出空间为 Y { 0 , 1 } \mathcal{Y} \{0,1\} Y{0,1}&#xff0c;学习目标为…

视频自动化分割方案:支持按时间与段数拆分

在日常视频处理任务中&#xff0c;如何快速将一个较长的视频文件按照指定规则拆分为多个片段&#xff0c;是许多用户都会遇到的问题。尤其对于需要批量处理视频的开发者、自媒体运营者或内容创作者来说&#xff0c;手动剪辑不仅效率低下&#xff0c;还容易出错。这是一款绿色免…

股指期货合约价值怎么算?

股指期货合约价值就是你买一手股指期货合约&#xff0c;理论上值多少钱。这个价值是根据期货的价格和合约乘数来计算的。就好比你买了一斤苹果&#xff0c;价格是5块钱一斤&#xff0c;那你买一斤就得付5块钱。股指期货也是一样&#xff0c;只不过它的计算稍微复杂一点点。 一…

【QT】使用QT帮助手册找控件样式

选择帮助—》输入stylesheet(小写)—》选择stylesheet—》右侧选择Qt Style Sheets Reference 2.使用CtrlF—》输入要搜索的控件—》点击Customizing QScrollBar 3.显示参考样式表–》即可放入QT-designer的样式表中

计算机网络(5)——数据链路层

1.概述 数据链路层负责一套链路上从一个节点向另一个物理链路直接相连的相邻节点传输数据报。换言之&#xff0c;主要解决相邻节点间的可靠数据传输 节点(nodes)&#xff1a;路由器和主机 链路(links)&#xff1a;连接相邻节点的通信信道 2.数据链路层服务 2.1 组帧 组帧(fra…