🏆本文收录于《聊设计模式》专栏,专门攻坚指数级提升,助你一臂之力,带你早日登顶🚀,欢迎持续关注&&收藏&&订阅!
前言
在软件开发中,我们常常需要处理树形结构的问题。树形结构通常由树枝和叶子节点组成,每个树枝可以有多个子节点或叶子节点。而组合模式(Composite
)就是一种处理树形数据结构的模式。
组合模式将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
摘要
组合模式是一种结构型设计模式。可以将对象组合成树形结构,以表示“部分-整体”的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性。
在本文中,我们通过一个示例程序来阐释组合模式的实现方式、优缺点、使用场景及注意事项。
组合模式
概念
组合模式是一种结构型设计模式,允许将对象组合成树形结构来表示部分-整体的层次结构。它使客户端可以像处理单个对象一样处理对象的组合。组合模式使用递归算法从而可以处理复杂的层次结构,同时保持简单的代码结构。在组合模式中,有两种基本类型的对象:叶子节点和组合节点。叶子节点表示树形结构中的单个元素,而组合节点则表示一个包含多个子节点的组合元素。通过这种方式,组合模式可以帮助我们在层次结构中自由地添加、删除和修改对象,同时不会破坏整个树形结构的完整性。
结构
组合模式包含以下角色:
Component
(抽象构件):它可以是接口或抽象类,为叶子构件和组合构件对象声明接口,实现所有类共有的接口默认行为,用于访问和管理Component
的子部件。Leaf
(叶子构件):在组合中表示子节点对象,叶子节点没有子节点。Composite
(组合构件):定义组合中的枝干节点行为,用于存储子部件,在Component
接口中实现与子部件有关的操作。
通过组合模式,我们可以将一个树形结构表示为一个对象,同时对于客户端而言,无论是访问树中的一个叶子节点还是一个枝干节点,都可以使用一致的方式进行操作。
下面是组合模式的 UML 类图:
优缺点
优点
缺点
使用场景
组合模式通常在以下场景中使用:
注意事项
instanceof
),否则会导致系统变得复杂;示例程序
本文以操作系统文件系统为例,来阐释组合模式的实现方式。文件系统由文件夹(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 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();
}
}
输出结果如下:
代码解读
这是一个演示组合模式的 Java
代码。组合模式是一种结构型模式,它将对象组合成树形结构以表示“部分-整体”的层次关系。组合模式使得用户对单个对象和组合对象的使用具有一致性。
在这个示例中,首先定义了一个 Component
接口,它包含了 add()
、remove()
和 display()
方法,用于添加、移除和展示组件。然后定义了两个具体的组件类:Folder
和 File
。其中 Folder
类具有一个 ArrayList
成员变量,用于存储它所包含的组件。
在 main()
方法中,首先创建了一个根节点 root
,然后创建了三个文件夹和三个文件,并将文件添加到对应的文件夹中。最后将三个文件夹添加到根节点下,并调用根节点的 display()
方法,展示整个组合结构。
输出结果类似于,如下:
root
---folder1
------file1
---folder2
------file2
---folder3
------file3
其中 - - - 表示缩进,表示嵌套的层次关系。
附录源码
如上涉及代码均已上传同步在 GitHub,提供给同学们参考性学习。
总结
本文介绍了组合模式的实现方式、优缺点、使用场景及注意事项,并通过一个文件系统示例程序进行了阐述。组合模式提供了一种处理树形结构数据的方式,它使得客户端代码可以一致地处理单个对象和组合对象。同时,我们也需要注意在实现过程中避免过多的类型判断,同时保证每个节点都有父节点的引用。
☀️建议/推荐你
如果想系统性的全面学习设计模式,建议小伙伴们直接毫无顾忌的关注这个专栏《聊设计模式》,无论你是想提升自己的编程技术,还是渴望更好地理解代码背后的设计思想,本专栏都会为你提供实用的知识和启发,帮助你更好地解决日常开发中的挑战,将代码变得更加优雅、灵活和可维护!
📣关于我
我是bug菌,CSDN | 掘金 | infoQ | 51CTO 等社区博客专家,历届博客之星Top30,掘金年度人气作者Top40,51CTO年度博主Top12,华为云 | 阿里云| 腾讯云等社区优质创作者,全网粉丝合计15w+ ;硬核微信公众号「猿圈奇妙屋」,欢迎你的加入!免费白嫖最新BAT互联网公司面试题、4000G pdf电子书籍、简历模板等海量资料。