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

组合模式结构

  • 抽象组件: 定义了组合对象和叶子对象的接口, 包括添加, 删除子组件以及其他共享的行为
  • 叶子节点: 代表组合中的叶子对象, 它没有子节点, 定义了对象的基本行为
  • 组合节点: 定义有子组件的那些对象, 存储子组件, 并实现抽象组件中的相关操作

组合模式实现

假设要实现一个文件系统, 包括文件和目录, 目录包含文件和子目录, 可以用组合模式来实现这个系统

// 抽象组件
abstract class FileSystemComponent {
public void add(FileSystemComponent component) {
throw new UnsupportedOperationException();
}

public void remove(FileSystemComponent component) {
throw new UnsupportedOperationException();
}

public FileSystemComponent getChild(int index) {
throw new UnsupportedOperationException();
}

public abstract void display(String indent);
}

// 叶子节点
class File extends FileSystemComponent {
private String name;

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

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

// 组合节点
class Directory extends FileSystemComponent {
private String name;
private List<FileSystemComponent> components = new ArrayList<>();

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

@Override
public void add(FileSystemComponent component) {
components.add(component);
}

@Override
public void remove(FileSystemComponent component) {
components.remove(component);
}

@Override
public FileSystemComponent getChild(int index) {
return components.get(index);
}

@Override
public void display(String indent) {
System.out.println(indent + "Directory: " + name);
for (FileSystemComponent component : components) {
component.display(indent + " ");
}
}
}

// 客户端代码
public class Client {
public static void main(String[] args) {
FileSystemComponent file1 = new File("File1.txt");
FileSystemComponent file2 = new File("File2.txt");
FileSystemComponent file3 = new File("File3.txt");

FileSystemComponent directory1 = new Directory("Directory1");
FileSystemComponent directory2 = new Directory("Directory2");

directory1.add(file1);
directory1.add(file2);

directory2.add(file3);
directory2.add(directory1);

directory2.display("");
}
}

优点:

  • 清晰的层次结构. 通过组合模式可以清晰地表示对象的部分-整体层次结构
  • 一致的处理方法: 客户端可以一致地使用组合对象和叶子对象, 无需关注它们的具体类型, 有助于提高系统的灵活性
  • 简化客户端代码: 客户端可以统一处理组合对象和叶子对象, 减少了处理不同对象类型的复杂性
  • 容易拓展: 可以很容易地添加新的组合对象和叶子对象而不会影响现有代码

缺点:

  • 类数目会增加
  • 子组件管理复杂