组合模式(Composite)

组合模式是一种结构型设计模式,主要用来将多个对象组织成树形结构以表示“部分-整体”的层次结构,因此该模式也称为“部分-整体”模式。简言之,组合模式就是用来将一组对象组合成树状结构,并且能像使用独立对象一样使用它们。

Composite is a structural design pattern that lets you organize multiple objects into a tree structure to represent the "part whole" relationship. In short, the composite pattern can be used to combine a group of objects into a tree structure and use them as independent objects.  

结构设计

为实现组合模式,首先需要创建一个可以组合多个对象的单一对象(Component),这个对象用来访问和管理其子对象,并对外提供公共接口。然后,定义没有子节点的对象(Leaf,基本对象)和包含子对象的对象(Composite,组合对象)。最后,将这些对象组装到之前创建的对象上。这样,外部(Client)就可通过Component调用公共接口。组合模式包含如下角色:
Component,组合对象,为组合中的对象声明公共接口,并提供默认实现。
Leaf,叶节点对象,叶节点最终会完成大部分的实际工作,因为它们无法将工作指派给其他部分。
Compoiste,组合,也称容器,包含叶节点或其他容器的单位。容器不知道其子项目所属的具体类, 它只通过通用的组件接口与其子项目交互。
组合模式类图表示如下:
请添加图片描述
注意:
(1) 组合模式对基本对象和组合对象的使用具有一致性。外部代码调用Component公共接口时,无需区别对待基本对象和组合对象(透明性),大多数情况下可以一致地处理它们。

伪代码实现

接下来将使用代码介绍下组合模式的实现。

// 1、Component,组合对象,为组合中的对象声明公共接口,并提供默认实现。  
public abstract class Component {
    private String name;

    protected List<Component> children = new ArrayList<>();

    public Component(String componentName) {
        this.name = componentName;
    }

    public void operation() {
        System.out.println(this.name);
    }

    public Component getChild(String componentName) {
        for (Component current : children) {
            if (current.name.equals(componentName)) {
                return current;
            }
            Component childComponent = current.getChild(componentName);
            if (childComponent != null) {
                return childComponent;
            }
        }
        return null;
    }

    public abstract void add(Component component);

    public abstract void remove(Component component);
}
// 2、Compoiste,组合,也称容器,包含叶节点或其他容器的单位。容器不知道其子项目所属的具体类,
// 它只通过通用的组件接口与其子项目交互。  
public class Composite extends Component {
    public Composite(String componentName) {
        super(componentName);
    }

    @Override
    public void add(Component component) {
        this.children.add(component);
    }

    @Override
    public void remove(Component component) {
        this.children.remove(component);
    }
}
// 3、Leaf,叶节点对象,叶节点最终会完成大部分的实际工作,因为它们无法将工作指派给其他部分。  
public class Leaf extends Component {
    public Leaf(String componentName) {
        super(componentName);
    }

    @Override
    public void add(Component component) {
        throw new RuntimeException("叶节点不能添加子节点");
    }

    @Override
    public void remove(Component component) {
        throw new RuntimeException("叶节点不包含子节点,无法移除子节点");
    }
}
// 4、客户端调用
public class CompositeClient {
    public void test() {
        Component root = new Composite("root");
        root.add(new Leaf("Leaf A"));
        Composite branch = new Composite("Composite X");
        Leaf leafXa = new Leaf("Leaf XA");
        branch.add(leafXa);
        branch.add(new Leaf("Leaf XB"));
        branch.remove(leafXa);
        root.add(branch);
        Component leafXb = root.getChild("Leaf XB");
        leafXb.operation();
    }
}

这里只介绍了基于透明性的设计与实现,组合模式还支持一种基于安全性的设计与实现,更多安全性相关知识可以执行搜索并学习。

适用场景

在以下情况下可以考虑使用组合模式:
(1) 如果需要实现树状对象结构, 可以考虑使用组合模式。
组合模式提供了两种共享公共接口的基本元素类型:简单叶节点和复杂容器。容器中可以包含叶节点和其他容器。这使得开发者可以构建树状嵌套递归对象结构。
(2) 如果希望客户端代码以相同方式处理简单和复杂元素, 可以使用该模式。
组合模式中定义的所有元素共用同一个接口。在这一接口的帮助下,客户端不必在意其所使用的对象的具体类。

优缺点

组合模式最大特点是将多个对象组织成树形结构。组合模式有以下优点:
(1) 可以利用多态和递归机制更方便地使用复杂树结构。
(2) 符合开闭原则。无需更改现有代码,开发者就可以在应用中添加新元素,使其成为对象树的一部分。
但是组合模式也存在以下缺点:
(1) 对于功能差异较大的类, 提供公共接口或许会有困难。在特定情况下,开发者需要过度一般化组件接口,使其变得令人难以理解。

参考

《设计模式:可复用面向对象软件的基础》 Erich Gamma, Richard Helm, Ralph Johnson, John Vlissides 著 李英军, 马晓星 等译
https://refactoringguru.cn/design-patterns/composite 组合模式
https://www.cnblogs.com/adamjwh/p/9033547.html 简说设计模式——组合模式
https://blog.csdn.net/ShuSheng0007/article/details/116378002 秒懂设计模式之组合模式(Composite Pattern)
https://www.runoob.com/design-pattern/composite-pattern.html 组合模式

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

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

相关文章

排序进行曲-v2.0

小程一言 这篇文章是在排序进行曲1.0之后的续讲&#xff0c; 0之后的续讲,英语在上一篇讲的排序的基本概念与分类0之后的续讲, 英语在上一篇讲的排序的基本概念与分类这片主要是对0之后的续讲,英语在上一篇讲的排序的基本概念与分类这 篇主要是对几个简单的排序进行细致的分析…

HarmonyOS/OpenHarmony元服务开发-配置卡片的配置文件

卡片相关的配置文件主要包含FormExtensionAbility的配置和卡片的配置两部分&#xff1a; 1.卡片需要在module.json5配置文件中的extensionAbilities标签下&#xff0c;配置FormExtensionAbility相关信息。FormExtensionAbility需要填写metadata元信息标签&#xff0c;其中键名称…

企业电子招投标采购系统java spring cloud+spring boot功能模块功能描述+数字化采购管理 采购招投标

​功能模块&#xff1a; 待办消息&#xff0c;招标公告&#xff0c;中标公告&#xff0c;信息发布 描述&#xff1a; 全过程数字化采购管理&#xff0c;打造从供应商管理到采购招投标、采购合同、采购执行的全过程数字化管理。通供应商门户具备内外协同的能力&#xff0c;为外…

Java枚举解析:掌握枚举的绝佳指南!

申明&#xff1a;本人于公众号Java筑基期&#xff0c;CSDN先后发当前文章&#xff0c;标明原创&#xff0c;转载二次发文请注明转载公众号&#xff0c;另外请不要再标原创 &#xff0c;注意违规 枚举 在Java中&#xff0c;枚举&#xff08;Enumeration&#xff09;是一种特殊的…

Python实现单例模式

一、介绍 单例模式是一种常见的设计模式&#xff0c;它保证一个类只能被实例化一次&#xff0c;并提供了一个全局访问点来获取这个唯一的实例。在Python中&#xff0c;可以通过使用装饰器、元类或模块等方式实现单例模式。 二、Python实现单例模式的6种方法 1、使用模块实现…

git 忽略掉不需要的文件

第一步&#xff1a;创建.gitignore文件 touch .gitignore 第二步&#xff1a;使用vi编辑器 输入不需要的文件&#xff0c;或用通配符*来忽视一系列文件 效果&#xff1a;

什么是软件检测证明材料,如何才能获得软件检测证明材料?

一、什么是软件检测证明材料 软件检测证明材料是指在软件开发和发布过程中&#xff0c;为了证明软件的质量和合法性&#xff0c;进行的一系列检测和测试的结果的集合。它是软件开发者和用户之间信任的桥梁&#xff0c;可以帮助用户了解软件的性能和安全性&#xff0c;让用户放…

开放自动化软件的硬件平台

自动化行业的产品主要以嵌入式系统为主&#xff0c;历来对产品硬件的可靠性和性能都提出很高的要求。最典型的产品要数PLC。PLC 要求满足体积小&#xff0c;实时性&#xff0c;可靠性&#xff0c;可扩展性强&#xff0c;环境要求高等特点。它们通常采用工业级高性能嵌入式SoC 实…

LinearAlgebraMIT_6_ColumnSpaceAndNullSpace

这节课的两个重点是column space列空间和null space零空间。 x.1 pre-multiply/left multiply and post-multiply/right multiply 对于pre-multiply/left multiply左乘和post-multiply/right multiply右乘&#xff0c;如果用英文的pre-和post-是比较容易理解的&#xff0c; A…

Maven发布项目到Nexus私服

项目pom配置 在项目pom.xml中文件中的仓库配置&#xff0c;Nexus私服如何搭建在这里不介绍了可自行百度。 <distributionManagement><repository><id>releases</id><name>Nexus Release Repository</name><url>http://私服地址:34…

gitlab CI/CD 安装 gitlab runner

一、为什么需要安装gitlab runner &#xff1f; 极狐GitLab Runner 极狐GitLab Runner 是在流水线中运行作业的应用&#xff0c;与极狐GitLab CI/CD 配合运作。 说白了就是你部署的一个agent。 二、如何安装&#xff1f; 1.介绍通过helm部署github runner 2.helm添加仓库 h…

python小游戏课程设计报告,python游戏课程设计报告

大家好&#xff0c;给大家分享一下python2048游戏课程设计报告&#xff0c;很多人还不知道这一点。下面详细解释一下。现在让我们来看看&#xff01;

Clion开发Stm32之温湿度传感器(DS18B20)驱动编写和测试

前言 涵盖之前文章: Clion开发STM32之HAL库GPIO宏定义封装(最新版)Clion开发stm32之微妙延迟(采用nop指令实现)Clion开发STM32之日志模块(参考RT-Thread) DSP18B20驱动文件 头文件 /*******************************************************************************Copy…

多线程(JavaEE初阶系列6)

目录 前言&#xff1a; 1.什么是线程池 2.标准库中的线程池 3.实现线程池 结束语&#xff1a; 前言&#xff1a; 在上一节中小编带着大家了解了一下Java标准库中的定时器的使用方式并给大家实现了一下&#xff0c;那么这节中小编将分享一下多线程中的线程池。给大家讲解一…

CNN卷积详解

转载自&#xff1a;https://blog.csdn.net/yilulvxing/article/details/107452153 仅用于自己学习过程中经典文章讲解的记录&#xff0c;防止原文失效。 1&#xff1a;单通道卷积 以单通道卷积为例&#xff0c;输入为&#xff08;1,5,5&#xff09;&#xff0c;分别表示1个通道…

安防视频监控平台EasyCVR修改参数提示database or disk is full的原因排查

EasyDarwin开源流媒体视频EasyCVR安防监控平台可提供视频监控直播、云端录像、云存储、录像检索与回看、智能告警、平台级联、云台控制、语音对讲、智能分析等能力。视频监控综合管理平台EasyCVR具备视频汇聚融合能力&#xff0c;平台基于云边端一体化架构&#xff0c;具有强大…

JDK各版本重要变革

各版本更新详情 JDK8(LTS)--2014/3 语法层面 lambda表达式(重要特色之一) 一种特殊的匿名内部类,语法更加简洁允许把函数作为一个方法的参数,将代码象数据一样传递&#xff0c;即将函数作为方法参数传递基本语法: <函数式接口> <变量名> (参数...) -> { 方法…

做虾皮你必须懂的五大流量运营逻辑!

一、竞品流量来源 商家排名一般有四个维度&#xff0c;弟一个维度是消量弟一&#xff0c;弟二个维度是销售额弟一&#xff0c;第三个维度是流量弟一&#xff0c;第四个维度利润弟一。只要我们找出来自我排名即可&#xff0c;然后打开生意参谋&#xff0c;到竞品分析添加成竞品…

【188】Java8利用AVL树实现Map

AVL树又被叫做平衡二叉搜索树、平衡二叉树。AVL是其发明者的首字母缩写。 这篇文章中&#xff0c;AVLTreeMap 类集成了 java.util.Map 接口&#xff0c;并利用 AVL 树结构实现了 Map 接口的所有方法。本文还给出了测试代码。 为什么要发明AVL树&#xff1f; 当我按照从小到大…

移动端商品分类左右联动

代码&#xff1a; <template><view class"u-wrap"><view class"u-menu-wrap"><scroll-view scroll-y scroll-with-animation class"u-tab-view menu-scroll-view" :scroll-top"scrollTop":scroll-into-view&quo…