组合模式处理"树形结构"——文件和文件夹、菜单和子菜单、部门和子部门。它让"单个对象"和"组合对象"对外表现一致,客户端不用区分。这篇讲清它怎么统一处理叶子和树枝。
一、解决什么问题:树形结构的统一处理
文件系统是典型的树形结构:文件夹里可以有文件,也可以有子文件夹。客户端想"遍历整个目录",得区分"这是文件(处理它)"还是"文件夹(递归进去)":
java
// 不用组合模式:客户端要判断类型,代码一堆 if
if (node instanceof File) {
((File) node).read();
} else if (node instanceof Folder) {
for (Node child : ((Folder) node).getChildren()) { ... } // 递归
}组合模式的思路:让"文件"和"文件夹"实现同一个接口,客户端统一调用,不用区分。
二、核心结构
java
// 抽象组件:文件和文件夹都实现它
interface FileSystemNode {
void print(String indent);
}
// 叶子:文件
class File implements FileSystemNode {
private String name;
public void print(String indent) { System.out.println(indent + name); }
}
// 树枝:文件夹,持有子节点列表
class Folder implements FileSystemNode {
private String name;
private List<FileSystemNode> children = new ArrayList<>();
void add(FileSystemNode node) { children.add(node); }
public void print(String indent) {
System.out.println(indent + name + "/");
for (FileSystemNode child : children) {
child.print(indent + " "); // 递归,但不用判断是文件还是文件夹
}
}
}关键:Folder.print() 里递归调用 child.print(),但不用判断 child 是 File 还是 Folder——因为它们都是 FileSystemNode,统一调 print 就行。
三、核心价值:统一"整体"和"部分"
组合模式让"单个对象"(文件)和"组合对象"(文件夹)对外表现一致,客户端可以把它们一视同仁:
- 客户端不用写
if (是文件) ... else if (是文件夹) ... - 加新节点类型(比如"快捷方式"),客户端代码不用改
四、实际应用
- 文件系统:文件和目录
- 菜单系统:菜单项(叶子)和子菜单(树枝)
- UI 组件树:按钮(叶子)和面板(树枝,能装其他组件)
小结
- 组合模式处理树形结构,让"叶子"和"树枝"实现同一接口
- 客户端统一调用,不用区分单个还是组合
- 典型场景:文件系统、菜单、UI 组件树
相关:《责任链模式》(同为链式结构,但组合是树、责任链是链)。
