组合模式(Composite Pattern)是一种结构型设计模式
,用于将对象组合成树形结构
以表示“部分-整体”的层次关系。它允许客户端以统一的方式处理单个对象和组合对象,无需关心具体是叶子节点还是容器节点。
核心思想
- 统一接口:定义统一的抽象接口,让叶子对象和容器对象具有一致的行为。
- 递归组合:容器对象可以包含其他容器或叶子对象,形成树状结构。
- 透明性:客户端无需区分操作的是单个对象还是组合对象。
组合模式结构
组合模式包含三个关键角色:
组件(Component)
定义:所有对象的通用接口(抽象类或接口)。
职责:声明管理子组件的方法(如 add()、remove()),以及业务方法(如 operation())。public abstract class Component { // 管理子组件的方法(默认抛出异常,叶子节点无需实现) public void add(Component component) { throw new UnsupportedOperationException(); } public void remove(Component component) { throw new UnsupportedOperationException(); } public List<Component> getChildren() { throw new UnsupportedOperationException(); } // 业务方法(由子类实现) public abstract void operation(); }
叶子节点(Leaf)
定义:树形结构中的基础元素,没有子节点。
职责:实现组件的业务方法,不实现子组件管理方法。public class Leaf extends Component { @Override public void operation() { System.out.println("执行叶子节点操作"); } }
容器节点(Composite)
定义:包含子组件(可以是叶子或其他容器)的复杂元素。
职责:实现子组件管理方法,并递归调用子组件的业务方法。public class Composite extends Component { private List<Component> children = new ArrayList<>(); @Override public void add(Component component) { children.add(component); } @Override public void remove(Component component) { children.remove(component); } @Override public List<Component> getChildren() { return children; } @Override public void operation() { System.out.println("执行容器节点操作"); // 递归调用子组件的 operation() for (Component child : children) { child.operation(); } } }
优缺点分析
优点
- 简化客户端代码:统一处理单个对象和组合对象。
- 开闭原则:易于添加新类型的组件。
- 灵活结构:支持动态构建复杂树形结构。
缺点
- 设计抽象:需合理设计组件接口,过度通用化可能增加复杂度。
- 类型检查:透明模式中需处理叶子节点不支持的方法调用。
代码示例:文件系统
假设需要表示一个文件系统中的文件和文件夹:
// 组件抽象类
public abstract class FileSystemComponent {
protected String name;
public FileSystemComponent(String name) {
this.name = name;
}
public void add(FileSystemComponent component) {
throw new UnsupportedOperationException();
}
public void remove(FileSystemComponent component) {
throw new UnsupportedOperationException();
}
public abstract void display();
}
// 叶子节点:文件
public class File extends FileSystemComponent {
public File(String name) {
super(name);
}
@Override
public void display() {
System.out.println("文件:" + name);
}
}
// 容器节点:文件夹
public class Directory extends FileSystemComponent {
private List<FileSystemComponent> children = new ArrayList<>();
public Directory(String name) {
super(name);
}
@Override
public void add(FileSystemComponent component) {
children.add(component);
}
@Override
public void remove(FileSystemComponent component) {
children.remove(component);
}
@Override
public void display() {
System.out.println("文件夹:" + name);
for (FileSystemComponent child : children) {
child.display();
}
}
}
// 客户端使用
public class Client {
public static void main(String[] args) {
FileSystemComponent root = new Directory("根目录");
FileSystemComponent file1 = new File("文档.txt");
FileSystemComponent file2 = new File("图片.jpg");
Directory subDir = new Directory("子文件夹");
subDir.add(new File("代码.java"));
root.add(file1);
root.add(file2);
root.add(subDir);
root.display();
}
}
// 输出:
// 文件夹:根目录
// 文件:文档.txt
// 文件:图片.jpg
// 文件夹:子文件夹
// 文件:代码.java
应用场景
适用场景
- 表示树形结构(如文件系统、组织架构、UI组件嵌套)。
- 希望客户端以统一方式处理简单元素和复杂元素。
- 需要动态添加或移除层次结构中的对象。
实际应用
- Java Swing:JComponent 作为组件,Container 作为容器。
- XML解析:DOM树中的元素和子元素。
- 企业组织架构:部门与员工的层级管理。
与其他模式的关系
- 与装饰器模式:组合模式关注结构组合,装饰器模式关注动态添加职责。
- 与迭代器模式:常结合使用,遍历组合结构中的元素。
- 与访问者模式:通过访问者统一处理不同节点类型。
总结
组合模式通过树形结构和统一接口,实现了部分-整体关系的优雅管理。在需要处理层次化数据的场景中(如UI组件、文件系统),它能显著提升代码的可维护性和扩展性。