组合模式介绍

news2024/12/28 20:55:04

目录

一、组合模式介绍

1.1组合模式定义

1.2 组合模式原理

1.2.1 组合模式类图

1.2.2 模式角色说明

1.2.3 示例代码

二、组合模式的应用

2.1 需求说明

2.2 需求实现

2.2.1 类图

2.2.2 具体实现

2.2.2.1 Entry抽象类

2.2.2.2 叶子节点

2.2.2.3 树枝节点

2.2.2.4 测试类

三、组合模式总结

3.1 组合模式的分类

3.1.1 透明组合模式

3.1.2 安全组合模式

3.2 组合模式的优点

3.3 组合模式的缺点

3.4 组合模式的适用场景


一、组合模式介绍

1.1组合模式定义

组合模式(Composite Pattern) 的定义是:将对象组合成树形结构以表示整个部分的层次结构。组合模式可以让用户统一对待单个对象和对象的组合。比如: windows操作系统中的目录结构,其实就是树形目录结构,通过tree命令实现树形结构展示。

在上图中包含了文件夹和文件两类不同元素,其中在文件夹中可以包含文件,还可以继续包含子文件夹。子文件夹中可以放入文件,也可以放入子文件夹。文件夹形成了一种容器结构(树形结构),递归结构。

接着我们再来思考虽然文件夹和文件是不同类型的对象,但是他们有一个共性,就是都可以被放入文件夹中。其实文件和文件夹可以被当做是同一种对象看待。组合模式其实就是将一组对象(文件夹和文件)组织成树形结构,以表示一种'部分整体' 的层次结构(目录与子目录的嵌套结构)。 组合模式让客户端可以统一单个对象(文件)和组合对象(文件夹)的处理逻辑(递归遍历)。组合模式更像是一种数据结构和算法的抽象,其中数据可以表示成树这种数据结构,业务需求可以通过在树上的递归遍历算法来实现。

1.2 组合模式原理

1.2.1 组合模式类图

1.2.2 模式角色说明

组合模式主要包含三种角色:

  • 抽象根节点(Component):

定义系统各层次对象的共有方法和属性,可以预先定义一些默认行为和属性。在该角色中可以包含所有子类共有行为的声明和实现。在抽象根节点中定义了访问及管理它的子构件的方法,如增加子节点、删除子节点、获取子节点等。

  • 树枝节点(Composite):

定义树枝节点的行为,存储子节点,组合树枝节点和叶子节点形成一个树形结构。树枝节点可以包含树枝节点,也可以包含叶子节点,它其中有一个集合可以用于存储子节点,实现了在抽象根节点中定义的行为.包括那些访问及管理子构件的方法,在其业务方法中可以递归调用其子节点的业务方法。

  • 叶子节点(Leaf):

叶子节点对象,其下再无分支,是系统层次遍历的最小单位。在组合结构中叶子节点没有子节点,它实现了在抽象根节点中定义的行为。

1.2.3 示例代码

package main.java.cn.test.composite.V1;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:08:08
 * @description 抽象根节点, 对于客户端而言将针对抽象编程, 无需关心其具体子类是容器构件还是叶子构件
 */
public abstract class Component {
    public abstract void add(Component c); //增加成员

    public abstract void remove(Component c); //删除成员

    public abstract Component getChild(int i); //获取成员

    public abstract void operation(); //业务方法
}

package main.java.cn.test.composite.V1;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:09:30
 * @description 叶子节点, 叶子节点中不能包含子节点
 */
public class Leaf extends Component {
    @Override
    public void add(Component c) {
        System.out.println("增加成员操作 ======");

    }

    @Override
    public void remove(Component c) {
        System.out.println("删除成员操作 ======");

    }

    @Override
    public Component getChild(int i) {
        return new Leaf();
    }

    @Override
    public void operation() {
       System.out.println("叶子节点具体业务方法 ======");
    }
}

package main.java.cn.test.composite.V1;

import java.util.ArrayList;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:12:35
 * @description 树枝节点, 可以包含子节点
 */
public class Composite extends Component {
    private ArrayList<Component> list = new ArrayList<>();

    @Override
    public void add(Component c) {
        list.add(c);
    }

    @Override
    public void remove(Component c) {
        list.remove(c);
    }

    @Override
    public Component getChild(int i) {
        return (Component) list.get(i);

    }

    @Override
    public void operation() {
        //在树枝节点中的业务方法,将递归调用其他节点中的operation()方法
        for (Component component : list) {
            component.operation();
        }

    }
}

二、组合模式的应用

2.1 需求说明

程序的功能是列出某一目录下所有的文件和文件夹

2.2 需求实现

2.2.1 类图

2.2.2 具体实现

2.2.2.1 Entry抽象类
package main.java.cn.test.composite.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:19:07
 * @description Entry抽象类, 表示目录条目(文件 + 文件夹)的抽象类
 */
public abstract class Entry {
    //获取文件名
    public abstract String getName();

    //获取文件大小
    public abstract int getSize();

    //添加文件夹或文件
    public abstract Entry add(Entry entry);

    //显示指定目录下的所有信息
    public abstract void printList(String prefix);

    @Override
    public String toString() {
        return getName() + "(" + getSize() + ")";
    }
}

2.2.2.2 叶子节点
package main.java.cn.test.composite.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:20:06
 * @description File类, 叶子节点, 表示文件
 */
public class File extends Entry {
    private String name; //文件名
    private int size; //文件大小

    public File(String name, int size) {
        this.name = name;
        this.size = size;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public int getSize() {
        return size;
    }

    @Override
    public Entry add(Entry entry) {
        return null;
    }

    @Override
    public void printList(String prefix) {
        System.out.println(prefix + "/" + this);
    }
}
2.2.2.3 树枝节点
package main.java.cn.test.composite.V2;

import java.util.ArrayList;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:21:39
 * @description Directory类, 树枝节点, 表示文件夹
 */
public class Directory extends Entry {
    //文件的名字
    private String name;
    //文件夹与文件的集合
    private ArrayList<Entry> directory = new ArrayList();

    //构造函数
    public Directory(String name) {
        this.name = name;
    }


    @Override
    public String getName() {
        return name;
    }

    /**
     * 获取文件大小
     * 1.如果entry对象是File类型,则调用getSize方法获取文件大小
     * 2.如果entry对象是Directory类型,会继续调用子文件夹的getSize方法,形成递归调用
     *
     * @return
     */
    @Override
    public int getSize() {
        int size = 0;
        //遍历或者去文件大小
        for (Entry entry : directory) {
            size += entry.getSize();
        }
        return size;

    }

    @Override
    public Entry add(Entry entry) {
        directory.add(entry);
        return this;
    }

    @Override
    public void printList(String prefix) {
        System.out.println("/" + this);
        for (Entry entry : directory) {
            entry.printList("/" + name);
        }
    }
}

2.2.2.4 测试类
package main.java.cn.test.composite.V2;

/**
 * @author ningzhaosheng
 * @date 2024/1/14 16:24:54
 * @description 测试类
 */
public class Test {
    public static void main(String[] args) {
        //根节点
        Directory rootDir = new Directory("root");
        //树枝节点
        Directory binDir = new Directory("bin");
        //向bin目录中添加叶子节点
        binDir.add(new File("vi", 10000));
        binDir.add(new File("test", 20000));
        Directory tmpDir = new Directory("tmp");
        Directory usrDir = new Directory("usr");
        Directory mysqlDir = new Directory("mysql");
        mysqlDir.add(new File("my.cnf", 30));
        mysqlDir.add(new File("test.db", 25000));
        usrDir.add(mysqlDir);
        rootDir.add(binDir);
        rootDir.add(tmpDir);
        rootDir.add(usrDir);
        rootDir.printList("");
    }
}

三、组合模式总结

3.1 组合模式的分类

3.1.1 透明组合模式

透明组合模式中,抽象根节点角色中声明了所有用于管理成员对象的方法,比如在示例中 Component 声明了 add 、 remove 、 getChild 方法,这样做的好处是确保所有的构件类都有相同的接口。透明组合模式也是组合模式的标准形式。
透明组合模式的缺点是不够安全,因为叶子对象和容器对象在本质上是有区别的,叶子对象不可能有下一个层次的对象,即不可能包含成员对象,因此为其提供 add()、remove() 等方法是没有意义的,这在编译阶段不会出错,但在运行阶段如果调用这些方法可能会出错(如果没有提供相应的错误处理代码)

3.1.2 安全组合模式

在安全组合模式中,在抽象构件角色中没有声明任何用于管理成员对象的方法,而是在树枝节点类中声明并实现这些方法。安全组合模式的缺点是不够透明,因为叶子构件和容器构件具有不同的方法,且容器构件中那些用于管理成员对象的方法没有在抽象构件类中定义,因此客户端不能完全针对抽象编程,必须有区别地对待叶子构件和容器构件。

3.2 组合模式的优点

  • 组合模式可以清楚地定义分层次的复杂对象,表示对象的全部或部分层次,它让客户端忽略了层次的差异,方便对整个层次结构进行控制。
  • 客户端可以一致地使用一个组合结构或其中单个对象,不必关心处理的是单个对象还是整个组合结构,简化了客户端代码。
  • 在组合模式中增加新的树枝节点和叶子节点都很方便,无须对现有类库进行任何修改,符合“开闭原则”。
  • 组合模式为树形结构的面向对象实现提供了一种灵活的解决方案,通过叶子节点和树枝节点的递归组合,可以形成复杂的树形结构,但对树形结构的控制却非常简单。

3.3 组合模式的缺点

  • 使用组合模式的前提在于,你的业务场景必须能够表示成树形结构。所以,组合模式的应用场景也 比较局限,它并不是一种很常用的设计模式。

3.4 组合模式的适用场景

  • 处理一个树形结构,比如,公司人员组织架构、订单信息等;
  • 跨越多个层次结构聚合数据,比如,统计文件夹下文件总数;
  • 统一处理一个结构中的多个对象,比如,遍历文件夹下所有 XML 类型文件内容。

好了,本次分享就到这里,欢迎大家继续阅读《设计模式》专栏其他设计模式内容,如果有帮助到大家,欢迎大家点赞+关注+收藏,有疑问也欢迎大家评论留言!

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

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

相关文章

C语言:自定义类型——联合和枚举

一、联合体 1.1 联合体类型的声明 像结构体⼀样&#xff0c;联合体也是由⼀个或者多个成员构成&#xff0c;这些成员可以是不同的类型。 声明方式如下图&#xff1a; 那联合体和结构体究竟有什么区别呢&#xff1f;&#xff1f; 下面将重点讲解联合体的特点&#xff01;&am…

Axure组件库免费下载,国内外资源都在这儿!

Axure 组件库具有高效再利用的价值。在设计中合理使用 Axure 组件库可以快速启动工作&#xff0c;避免重复简单的劳动&#xff0c;减轻设计师的负担&#xff0c;从而大大提高团队的生产力。在本文中&#xff0c;我们将分享如何下载 Axure 组件库&#xff0c;并附上 Axure 组件库…

【好书推荐-第四期】《Go专家编程(第2版)》华为资深技术专家力作,第1版评分9.4,适合Go程序员面试

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主、前后端开发、人工智能研究生。公粽号&#xff1a;程序员洲洲。 &#x1f388; 本文专栏&#xff1a;本文…

东北编程语言???

在GitHub闲逛&#xff0c;偶然发现了东北编程语言&#xff1a; 东北编程语言是由Zhanyong Wan创造的&#xff0c;它使用东北方言词汇作为基本关键字。这种编程语言的特点是简单易懂&#xff0c;适合小学文化程度的人学习&#xff0c;并且易于阅读、编写和记忆。它的语法与其他编…

什么样的耳机适合游泳?游泳耳机对人体有危害吗?

游泳是一项深受大家喜爱的运动&#xff0c;不仅可以锻炼身体&#xff0c;还能让我们享受到水中的乐趣。然而&#xff0c;对于喜欢在水中听音乐的人来说&#xff0c;选择一款适合游泳的耳机就显得尤为重要了。 游泳耳机是一种专为水上运动设计的防水耳机&#xff0c;可以在游泳、…

Qt 国产嵌入式操作系统实现文字转语音功能(TTS)

1.简介 本示例使用的CPU&#xff1a;rk3588。 操作系统&#xff1a;kylin V10 架构&#xff1a;aarch64 在Windows端&#xff0c;我们很容易想到使用Qt自带的类QTextToSpeech来实现文字转语音功能&#xff0c;Qt版本得在5.11.0以上才支持。但是在嵌入式平台&#xff0c;尤其…

GC9008 12V 全桥驱动芯片,可替代TMI8118,应用于摄像机、消费类产品上

GC9008 是一款 12V 全桥驱动芯片&#xff0c;为提供高性价比的方案。它能提供 0.1A 的持续输出电流。可以工作在 4.5~15V 的电源电压上。 具有 PWM&#xff08;IN1/IN2&#xff09;输入接口,与行业标准器件兼容.是 SOP8封装&#xff0c;GC9008D是DIP封装 芯片特点 ● H 桥电机…

2011 年考研数二真题解析

一、选择题 【01】【02】【03】【04】【05】【06】【07】【08】 二、填空题 【09】【10】【11】【12】【13】【14】 三、解答题 【15】【16】【17】【18】【19】【20】【21】【22】【23】

nxp s32k144芯片使用J-LINK程序刷写

1.nxp s32k144 (1)打开软件&#xff1a;J-Flash V6.30j (2)新建工程&#xff1a;file->new project (3)选择芯片型号和 target interface (4)可以保存芯片和接口配置 (5)打开程序&#xff1a;File->open data file &#xff08;6&#xff09;程序刷写&#xff1a;T…

hf-mirror 使用

文章目录 命令下载搜索下载gated model 根据这篇文章&#xff1a; 大模型下载使我痛苦 得知 Huggingface 镜像站 https://hf-mirror.com 命令下载 网站首页会介绍下载方法 更多用法&#xff08;多线程加速等&#xff09;详见这篇文章。简介&#xff1a; 方法一&#xff1a;…

Unity | 渡鸦避难所-7 | 攻击碰撞检测

1 前言 英雄的宝剑并非只是装饰物&#xff0c;利剑出鞘时可以对怪物造成伤害。同样&#xff0c;怪物挥出铁拳时也会对英雄造成伤害。当然&#xff0c;都有同样的前提&#xff1a;在武器碰到对方的情况下&#xff0c;才会造成伤害。利用物理引擎&#xff0c;可以轻松的实现碰撞…

网络攻击与检测防御:维护数字安全的关键挑战

随着数字化时代的深入&#xff0c;网络攻击已成为企业和个人面临的严峻挑战之一。本文将深入探讨不同类型的网络攻击&#xff0c;以及有效的检测和防御策略&#xff0c;以确保网络系统的安全性和稳定性。 1. 常见网络攻击类型&#xff1a; DDoS 攻击&#xff1a;分布式拒绝服…

[java数据结构] ArrayList和LinkedList介绍与使用

目录 (一) 线性表 (二) ArrayList 1. ArrayList的介绍 2. ArrayList的常见方法和使用 3. ArrayList的遍历 4. ArrayList的模拟实现 5. ArrayList的优缺点 (三) LinkedList 1. LinkedList的介绍 2. LinkedList的常见方法和使用 3. LinkedList的遍历 4. LinkedList的…

C++多线程学习[四]:多线程的通信和同步、互斥锁、超时锁、共享锁

一、多线程的状态 初始化 &#xff08;Init&#xff09;&#xff1a;该线程正在被创建。就绪 &#xff08;Ready&#xff09;&#xff1a;该线程在就绪列表中&#xff0c;等待CPU的调度。运行 &#xff08;Running&#xff09;&#xff1a;该线程正在运行。阻塞&#xff08;Bl…

AI智能化办公:巧用ChatGPT高效搞定Excel数据分析

文章目录 1. 自动提取关键信息2. 自动生成分析报告3. 自动回答问题4. 自动生成图表《巧用ChatGPT高效搞定Excel数据分析》关键点内容简介作者简介 《AI智能化办公&#xff1a;ChatGPT使用方法与技巧从入门到精通》图书特色内容简介作者简介 随着人工智能技术的不断发展&#xf…

【服务器数据恢复】服务器迁移数据时lun数据丢失的数据恢复案例

服务器数据恢复环境&服务器故障&#xff1a; 一台安装Windows操作系统的服务器。工作人员在迁移该服务器中数据时突然无法读取数据&#xff0c;服务器管理界面出现报错。经过检查发现服务器中一个lun的数据丢失。 服务器数据恢复过程&#xff1a; 1、将故障服务器中所有磁盘…

Java 10_000 代表什么意思? 数字里面混夹着下划线?

先放一张图 &#xff0c;这到底是sleep了多久&#xff1f; public static void main(String[] args) {int a 10_000; System.out.println(a); // 10000} java 7 的 特性 &#xff1a;https://docs.oracle.com/javase/7/docs/technotes/guides/language/underscores-literals…

开发需求总结9-el-tree获取选中节点,节点全选时返回被全选子级的父节点,未全选则返回被选中的节点

目录 需求描述 代码实现&#xff1a; 需求描述 需要获取树组件选中的节点&#xff0c;假如父节点被选中&#xff08;该节点全选&#xff09;&#xff0c;即只返回父节点的数据&#xff0c;如父节点未被全选&#xff0c;则正常返回被选中节点的数据。 示例一&#xff1a; 如上图…

未来科技五年人工智能行业产业发展趋势最新竞争力

人工智能&#xff08;Artificial Intelligence&#xff0c;AI&#xff09;是近年来快速发展的热门领域&#xff0c;被广泛应用于各个行业。随着技术的不断创新和突破&#xff0c;人工智能行业的竞争力也在不断提升。本文将分析未来科技五年人工智能行业产业发展趋势&#xff0c…

群发邮件的免费软件?做外贸用什么邮箱好?

群发邮件的免费软件有哪些&#xff1f;好用的邮件群发软件&#xff1f; 在数字时代&#xff0c;邮件已成为人们沟通的主要方式之一。有时候&#xff0c;我们需要给大量的联系人发送信息&#xff0c;这时候&#xff0c;群发邮件就显得格外重要。接下来蜂邮就来探讨一下那些值得…