设计模式——组合模式
一、什么是组合模式
组合模式(Composite Pattern)是一种结构型设计模式,用于将对象组合成树形结构以表示"整体-部分"的层次关系。通过让客户端以统一的方式处理单个对象和组合对象,实现了对树形结构中所有节点的透明化操作。
核心思想:通过共享接口,使得叶子节点(单个对象)和容器节点(组合对象)可以被一致对待,客户端无需关心操作的是单个对象还是组合结构。
二、结构组成
组件接口(Component)
- 声明组合对象的统一接口
- 定义默认行为(如add/remove/getChild等)
- 可声明访问/管理子组件的接口
叶子节点(Leaf)
- 表示组合中的叶子对象(无子节点)
- 实现组件接口定义的基础操作
复合节点(Composite)
- 存储子组件(Leaf或其他Composite)
- 实现与子组件相关的操作(如添加/删除子节点)
- 将请求委托给所有子组件
三、应用场景
- 需要表示树形对象结构(如文件系统、组织架构)
- 希望对整体和部分使用统一接口的场景
- GUI组件树(如包含子控件的容器控件)
- 递归处理数据结构(如XML/JSON解析)
- 数学表达式计算(操作数和操作符的组合)
四、实现
组件(Component):首先,我们定义一个基础接口 FileComponent,它是所有文件系统组件的基础,无论是文件还是文件夹都需要实现这个接口。
import java.util.ArrayList;
import java.util.List;
interface FileComponent {
void printPath(String prefix);
}
然后,我们定义两个类:Folder(组合节点) 和 File(叶子节点)。Folder 类是一个组合节点,它可以包含其他 FileComponent 对象;File 类是一个叶子节点,它代表一个单一的文件。
叶子结点:
class File implements FileComponent {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void printPath(String prefix) {
System.out.println(prefix + "/" + this.name);
}
}
组合节点:
class Folder implements FileComponent {
private String name;
private List<FileComponent> children = new ArrayList<>();
public Folder(String name) {
this.name = name;
}
public void add(FileComponent component) {
children.add(component);
}
public void remove(FileComponent component) {
children.remove(component);
}
@Override
public void printPath(String prefix) {
// 先打印自己本身
System.out.println(prefix + "/" + this.name);
// 再递归打印孩子
for (FileComponent child : children) {
child.printPath(prefix + "/" + this.name);
}
}
}
最后创建测试类。
public class FileSystemTree {
public static void main(String[] args) {
FileComponent root = new Folder("root");
FileComponent file1 = new File("file1.txt");
FileComponent subFolder = new Folder("subfolder");
FileComponent file2 = new File("file2.txt");
// Add components to the folder structure
root.add(file1);
root.add(subFolder);
subFolder.add(file2);
// Print the path of each component in the tree
root.printPath("");
}
}
// 打印结果
/root
/root/subfolder
/root/subfolder/file2.txt
/root/file1.txt
在这个例子中,FileComponent 接口定义了一个方法 printPath,该方法打印出当前文件或文件夹的路径。Folder 类实现了添加和移除子项的功能,并且递归地打印出所有子文件和子文件夹的路径。File 类简单地打印自己的路径。
五、优缺点分析
优点:
- 统一接口:组合模式提供了一致的接口来处理单个对象和组合对象。这意味着客户端代码可以使用相同的接口来操作组件,而不需要知道具体处理的是单个对象还是复合对象。这简化了客户端代码的设计。
- 易于扩展:使用组合模式可以很容易地扩展新的组件类型。只要新组件遵守相同的接口,就可以无缝地集成到现有的结构中
- 代码复用:组合模式使得代码可以在单个对象和组合对象之间复用,因为它们都实现了相同的接口。
- 灵活的层次结构:组合模式非常适合用来表示具有层次关系的对象结构。例如,文件系统、组织结构图等,都可以利用组合模式来表示。
- 支持递归操作:由于组合模式中的对象是以树形结构组织的,所以它天然支持递归的操作,比如遍历所有的子节点。
- 简化高层模块:高层模块只需要关心Component对象, 而不需要关心它到底是Composite还是Leaf,这使得高层模块更加简洁。
缺点:
能引入不必要的复杂性(特别是在对象层次比较简单的情况下)。以及可能消耗更多的内存。
觉得有帮助的话,点个赞或关注再走呗。
什么是精神内耗?
简单地说,就是心理戏太多,自己消耗自己。
所谓:
言未出,结局已演千百遍;
身未动,心中已过万重山;
行未果,假想灾难愁不展;
事已闭,过往仍在脑中演。