组合模式
简介
定义: 将对象组合成树形结构以表示"部分-整体"的层次结构。
使用场景:
文件系统(文件和文件夹)
组织架构树
UI组件树
菜单结构
实现要点:
统一的组件接口
叶子节点和容器节点
递归结构
UML
代码示例
一个文件系统组件抽象接口。
public interface FileSystemComponent {
/**
* 获取名称
*/
String getName();
/**
* 获取大小(字节)
*/
long getSize();
/**
* 显示组件信息
*/
void display(String prefix);
/**
* 添加子组件(仅容器节点有效)
*/
default void add(FileSystemComponent component) {
throw new UnsupportedOperationException("不支持添加操作");
}
/**
* 删除子组件(仅容器节点有效)
*/
default void remove(FileSystemComponent component) {
throw new UnsupportedOperationException("不支持删除操作");
}
/**
* 获取子组件(仅容器节点有效)
*/
default FileSystemComponent getChild(int index) {
throw new UnsupportedOperationException("不支持获取子组件操作");
}
/**
* 是否为容器节点
*/
boolean isContainer();
}组合模式的子节点
public class Folder implements FileSystemComponent {
private String name;
private List<FileSystemComponent> children;
public Folder(String name) {
this.name = name;
this.children = new ArrayList<>();
}
@Override
public String getName() {
return name;
}
@Override
public long getSize() {
long totalSize = 0;
for (FileSystemComponent component : children) {
totalSize += component.getSize();
}
return totalSize;
}
@Override
public void display(String prefix) {
System.out.println(prefix + "📁 " + name + " (" + formatSize(getSize()) + ")");
for (FileSystemComponent component : children) {
component.display(prefix + " ");
}
}
@Override
public void add(FileSystemComponent component) {
children.add(component);
}
@Override
public void remove(FileSystemComponent component) {
children.remove(component);
}
@Override
public FileSystemComponent getChild(int index) {
if (index >= 0 && index < children.size()) {
return children.get(index);
}
return null;
}
@Override
public boolean isContainer() {
return true;
}
/**
* 获取子组件数量
*/
public int getChildCount() {
return children.size();
}
/**
* 格式化文件大小显示
*/
private String formatSize(long size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return String.format("%.1f KB", size / 1024.0);
} else if (size < 1024 * 1024 * 1024) {
return String.format("%.1f MB", size / (1024.0 * 1024.0));
} else {
return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
}组合模式的叶子
public class File implements FileSystemComponent {
private String name;
private long size;
public File(String name, long size) {
this.name = name;
this.size = size;
}
@Override
public String getName() {
return name;
}
@Override
public long getSize() {
return size;
}
@Override
public void display(String prefix) {
System.out.println(prefix + "📄 " + name + " (" + formatSize(size) + ")");
}
@Override
public boolean isContainer() {
return false;
}
/**
* 格式化文件大小显示
*/
private String formatSize(long size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return String.format("%.1f KB", size / 1024.0);
} else if (size < 1024 * 1024 * 1024) {
return String.format("%.1f MB", size / (1024.0 * 1024.0));
} else {
return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
}
使用方式
public class Test {
public static void main(String[] args) {
System.out.println("=== 组合模式 - 文件系统示例 ===\n");
// 创建根目录
Folder root = new Folder("项目根目录");
// 创建文档文件夹
Folder documents = new Folder("文档");
documents.add(new File("需求文档.docx", 2 * 1024 * 1024)); // 2MB
documents.add(new File("设计文档.pdf", 5 * 1024 * 1024)); // 5MB
documents.add(new File("API文档.md", 512 * 1024)); // 512KB
// 创建源代码文件夹
Folder sourceCode = new Folder("源代码");
// Java源代码子文件夹
Folder javaCode = new Folder("java");
javaCode.add(new File("Main.java", 1024)); // 1KB
javaCode.add(new File("Utils.java", 2048)); // 2KB
javaCode.add(new File("Service.java", 3072)); // 3KB
// 配置文件子文件夹
Folder config = new Folder("config");
config.add(new File("application.properties", 512)); // 512B
config.add(new File("logback.xml", 1024)); // 1KB
// 将子文件夹添加到源代码文件夹
sourceCode.add(javaCode);
sourceCode.add(config);
// 创建资源文件夹
Folder resources = new Folder("resources");
resources.add(new File("logo.png", 256 * 1024)); // 256KB
resources.add(new File("banner.jpg", 1 * 1024 * 1024)); // 1MB
// 创建测试文件夹
Folder tests = new Folder("测试");
tests.add(new File("UnitTest.java", 1536)); // 1.5KB
tests.add(new File("IntegrationTest.java", 2048)); // 2KB
// 将主要文件夹添加到根目录
root.add(documents);
root.add(sourceCode);
root.add(resources);
root.add(tests);
// 添加一些根目录下的直接文件
root.add(new File("README.md", 1024)); // 1KB
root.add(new File("pom.xml", 2048)); // 2KB
// 显示整个文件系统结构
System.out.println("文件系统结构:");
root.display("");
System.out.println("\n=== 组合模式操作演示 ===");
// 演示统一操作 - 计算总大小
System.out.println("项目总大小: " + formatSize(root.getSize()));
System.out.println("文档文件夹大小: " + formatSize(documents.getSize()));
System.out.println("源代码文件夹大小: " + formatSize(sourceCode.getSize()));
// 演示动态添加文件
System.out.println("\n--- 动态添加文件 ---");
FileSystemComponent newFile = new File("新增文件.txt", 1024);
documents.add(newFile);
System.out.println("添加新文件后,文档文件夹大小: " + formatSize(documents.getSize()));
// 演示删除文件
System.out.println("\n--- 删除文件 ---");
documents.remove(newFile);
System.out.println("删除文件后,文档文件夹大小: " + formatSize(documents.getSize()));
// 演示遍历子组件
System.out.println("\n--- 遍历子组件 ---");
System.out.println("根目录下的子组件数量: " + root.getChildCount());
for (int i = 0; i < root.getChildCount(); i++) {
FileSystemComponent child = root.getChild(i);
System.out.println(" " + (i + 1) + ". " + child.getName() +
" (" + (child.isContainer() ? "文件夹" : "文件") + ")");
}
System.out.println("\n=== 组合模式特点总结 ===");
System.out.println("1. 统一接口: 文件和文件夹都实现FileSystemComponent接口");
System.out.println("2. 递归结构: 文件夹可以包含文件和子文件夹");
System.out.println("3. 透明性: 客户端可以统一处理文件和文件夹");
System.out.println("4. 扩展性: 易于添加新的文件系统组件类型");
}
/**
* 格式化文件大小显示
*/
private static String formatSize(long size) {
if (size < 1024) {
return size + " B";
} else if (size < 1024 * 1024) {
return String.format("%.1f KB", size / 1024.0);
} else if (size < 1024 * 1024 * 1024) {
return String.format("%.1f MB", size / (1024.0 * 1024.0));
} else {
return String.format("%.1f GB", size / (1024.0 * 1024.0 * 1024.0));
}
}
}Last updated
Was this helpful?