「聊设计模式」之组合模式(Composite)

举报
bug菌 发表于 2023/09/25 17:43:34 2023/09/25
【摘要】 组合模式是一种结构型设计模式,可以将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。


🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!


大家下午好,我是bug菌,今天我们继续聊设计模式。

前言

  在软件开发中,我们常常需要处理树形结构的问题。树形结构通常由树枝和叶子节点组成,每个树枝可以有多个子节点或叶子节点。而组合模式(Composite)就是一种处理树形数据结构的模式。

  组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

摘要

  组合模式是一种结构型设计模式。可以将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。

  在本文中,我们通过一个示例程序来阐释组合模式的实现方式、优缺点、使用场景及注意事项。

组合模式

概念

  组合模式是一种结构型设计模式,允许将对象组合成树形结构来表示部分-整体的层次结构。它使客户端可以像处理单个对象一样处理对象的组合。组合模式使用递归算法从而可以处理复杂的层次结构,同时保持简单的代码结构。在组合模式中,有两种基本类型的对象:叶子节点和组合节点。叶子节点表示树形结构中的单个元素,而组合节点则表示一个包含多个子节点的组合元素。通过这种方式,组合模式可以帮助我们在层次结构中自由地添加、删除和修改对象,同时不会破坏整个树形结构的完整性。

结构

组合模式包含以下角色:

  • Component(抽象构件):它可以是接口或抽象类,为叶子构件和组合构件对象声明接口,实现所有类共有的接口默认行为,用于访问和管理 Component 的子部件。
  • Leaf(叶子构件):在组合中表示子节点对象,叶子节点没有子节点。
  • Composite(组合构件):定义组合中的枝干节点行为,用于存储子部件,在 Component 接口中实现与子部件有关的操作。

  通过组合模式,我们可以将一个树形结构表示为一个对象,同时对于客户端而言,无论是访问树中的一个叶子节点还是一个枝干节点,都可以使用一致的方式进行操作。

下面是组合模式的 UML 类图:

image.png

优缺点

优点

  1. 可以清晰地定义复杂对象的层次结构;
  2. 客户端代码可以一致地处理单个对象和组合对象。

缺点

  1. 组合模式在增加新的构件时很难对系统的复杂度进行限制。

应用场景

组合模式通常在以下场景中使用:

  1. 表示对象的部分-整体层次结构;
  2. 让客户端统一处理单个对象和组合对象。

注意事项

  1. 不建议在组合模式中使用过多的类型判断(如 instanceof),否则会导致系统变得复杂;
  2. 程序中每个节点最好都有父节点的引用,方便操作。

模式实现

  本文以操作系统文件系统为例,来阐释组合模式的实现方式。文件系统由文件夹(Folder)和文件(File)组成,其中文件夹可以包含多个文件夹或文件,而文件没有子节点。

我们先定义一个抽象的文件系统节点 Component

package com.example.javaDesignPattern.composite;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:32
 */
public abstract class Component {
    protected String name;

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

    public abstract void add(Component c);

    public abstract void remove(Component c);

    public abstract void display();
}

  该类定义了文件系统中节点的公共属性和方法,其中 add()remove()用于添加/移除子节点,display() 用于展示当前节点信息。

然后定义叶子节点 File:

package com.example.javaDesignPattern.composite;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:33
 */
public class File extends Component {
    public File(String name) {
        super(name);
    }

    @Override
    public void add(Component c) {
        System.out.println("File cannot add any component");
    }

    @Override
    public void remove(Component c) {
        System.out.println("File cannot remove any component");
    }

    @Override
    public void display() {
        System.out.println("File Name: " + name);
    }
}

  该类表示文件节点,它没有子节点,因此 add()remove() 操作无法实现。

最后定义组合节点 Folder

public class Folder extends Component {
    private List<Component> children = new ArrayList<>();

    public Folder(String name) {
        super(name);
    }

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

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

    @Override
    public void display() {
        System.out.println("Folder Name: " + name);
        for (Component c : children) {
            c.display();
        }
    }
}

  该类表示文件夹节点,它可以包含多个子节点,因此实现了 add()remove() 操作,并在 display() 中递归展示子节点信息。

我们可以使用如下方式测试程序:

package com.example.javaDesignPattern.composite;

/**
 * @author bug菌
 * @version 1.0
 * @date 2023/9/19 14:34
 */
public class CompositeTest {
    public static void main(String[] args) {
        Component root = new Folder("root");
        Component folder1 = new Folder("folder1");
        Component folder2 = new Folder("folder2");
        Component folder3 = new Folder("folder3");

        Component file1 = new File("file1");
        Component file2 = new File("file2");
        Component file3 = new File("file3");

        folder1.add(file1);
        folder2.add(file2);
        folder3.add(file3);

        root.add(folder1);
        root.add(folder2);
        root.add(folder3);

        root.display();
    }
}

输出结果如下:

image.png

代码解读

  这是一个演示组合模式的 Java 代码。组合模式是一种结构型模式,它将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性。

  在这个示例中,首先定义了一个 Component 接口,它包含了 add()remove()display() 方法,用于添加、移除和展示组件。然后定义了两个具体的组件类:FolderFile。其中 Folder 类具有一个 ArrayList 成员变量,用于存储它所包含的组件。

  在 main() 方法中,首先创建了一个根节点 root,然后创建了三个文件夹和三个文件,并将文件添加到对应的文件夹中。最后将三个文件夹添加到根节点下,并调用根节点的 display() 方法,展示整个组合结构。

输出结果类似于,如下:

root
---folder1
------file1
---folder2
------file2
---folder3
------file3

其中 - - - 表示缩进,表示嵌套的层次关系。

小结

  本文介绍了组合模式的概念、特点和实现方式,并以操作系统文件系统为例,详细讲解了如何使用组合模式实现一个树形结构。组合模式是一种结构型设计模式,它可以将对象组合成树形结构,以描述部分和整体的层次结构,通过组合模式可以让客户端对单个对象和组合对象的使用具有一致性,使得系统更加灵活、可扩展、易维护。在具体应用中,需要根据实际情况选择是否使用组合模式,以达到最优的设计效果。本文介绍了组合模式的概念、特点和实现方式,并以操作系统文件系统为例,详细讲解了如何使用组合模式实现一个树形结构。组合模式是一种结构型设计模式,它可以将对象组合成树形结构,以描述部分和整体的层次结构,通过组合模式可以让客户端对单个对象和组合对象的使用具有一致性,使得系统更加灵活、可扩展、易维护。在具体应用中,需要根据实际情况选择是否使用组合模式,以达到最优的设计效果。

附录源码

  如上涉及代码均已上传同步在 GitHub,提供给同学们参考性学习。

总结

  本文介绍了组合模式的实现方式、优缺点、使用场景及注意事项,并通过一个文件系统示例程序进行了阐述。组合模式提供了一种处理树形结构数据的方式,它使得客户端代码可以一致地处理单个对象和组合对象。同时,我们也需要注意在实现过程中避免过多的类型判断,同时保证每个节点都有父节点的引用。

☀️建议/推荐你


  如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!

  最后,如果这篇文章对你有所帮助,帮忙给作者来个一键三连,关注、点赞、收藏,您的支持就是我坚持写作最大的动力。

  同时欢迎大家关注公众号:「猿圈奇妙屋」 ,以便学习更多同类型的技术文章,免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板、技术文章Markdown文档等海量资料。

📣关于我

  我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。


【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。