组合模式 (Composite Pattern)
模式定义
组合模式是一种结构型设计模式,它将对象组合成树形结构以表示"部分-整体"的层次结构,使得用户对单个对象和组合对象的使用具有一致性。
核心概念
- Component(组件): 为叶子和容器声明统一接口
- Leaf(叶子): 没有子节点的节点
- Composite(容器): 包含子节点的节点
实现示例:文件系统
组件接口
java
// 文件系统组件接口
public abstract class FileSystemComponent {
protected String name;
public FileSystemComponent(String name) {
this.name = name;
}
// 获取大小
public abstract int getSize();
// 显示结构
public abstract void display(String prefix);
// 以下操作仅对容器有意义,叶子实现抛出异常
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 String getName() {
return name;
}
}叶子节点(文件)
java
// 文件
public class File extends FileSystemComponent {
private final int size; // 文件大小(KB)
public File(String name, int size) {
super(name);
this.size = size;
}
@Override
public int getSize() {
return size;
}
@Override
public void display(String prefix) {
System.out.println(prefix + "📄 " + name + " (" + size + "KB)");
}
}容器节点(文件夹)
java
// 文件夹
public class Folder extends FileSystemComponent {
private final List<FileSystemComponent> children = new ArrayList<>();
public Folder(String name) {
super(name);
}
@Override
public void add(FileSystemComponent component) {
children.add(component);
}
@Override
public void remove(FileSystemComponent component) {
children.remove(component);
}
@Override
public FileSystemComponent getChild(int index) {
return children.get(index);
}
@Override
public int getSize() {
int totalSize = 0;
for (FileSystemComponent child : children) {
totalSize += child.getSize();
}
return totalSize;
}
@Override
public void display(String prefix) {
System.out.println(prefix + "📁 " + name + " (" + getSize() + "KB)");
for (FileSystemComponent child : children) {
child.display(prefix + " ");
}
}
}使用示例
java
public class CompositeDemo {
public static void main(String[] args) {
// 创建文件
FileSystemComponent file1 = new File("README.md", 5);
FileSystemComponent file2 = new File("Main.java", 15);
FileSystemComponent file3 = new File("Utils.java", 8);
FileSystemComponent file4 = new File("config.yml", 2);
FileSystemComponent file5 = new File("style.css", 12);
FileSystemComponent file6 = new File("index.html", 6);
// 创建文件夹
Folder srcFolder = new Folder("src");
srcFolder.add(file2);
srcFolder.add(file3);
Folder resourcesFolder = new Folder("resources");
resourcesFolder.add(file4);
Folder webFolder = new Folder("web");
webFolder.add(file5);
webFolder.add(file6);
// 构建树结构
Folder root = new Folder("project");
root.add(file1);
root.add(srcFolder);
root.add(resourcesFolder);
root.add(webFolder);
// 显示整个目录结构
root.display("");
System.out.println("\n项目总大小: " + root.getSize() + "KB");
}
}输出:
📁 project (48KB)
📄 README.md (5KB)
📁 src (23KB)
📄 Main.java (15KB)
📄 Utils.java (8KB)
📁 resources (2KB)
📄 config.yml (2KB)
📁 web (18KB)
📄 style.css (12KB)
📄 index.html (6KB)
项目总大小: 48KB实现示例:组织架构
组件接口
java
// 组织成员接口
public abstract class OrganizationComponent {
protected String name;
protected String description;
public OrganizationComponent(String name, String description) {
this.name = name;
this.description = description;
}
public abstract int getMemberCount();
public abstract void display(int depth);
public void add(OrganizationComponent component) {
throw new UnsupportedOperationException();
}
public void remove(OrganizationComponent component) {
throw new UnsupportedOperationException();
}
public String getName() { return name; }
public String getDescription() { return description; }
}叶子节点(员工)
java
// 员工
public class Employee extends OrganizationComponent {
private final String position;
private final double salary;
public Employee(String name, String position, double salary) {
super(name, name + " - " + position);
this.position = position;
this.salary = salary;
}
@Override
public int getMemberCount() {
return 1;
}
@Override
public void display(int depth) {
String indent = " ".repeat(depth);
System.out.println(indent + "👤 " + name + " (" + position + ")");
}
}容器节点(部门)
java
// 部门
public class Department extends OrganizationComponent {
private final List<OrganizationComponent> members = new ArrayList<>();
public Department(String name, String description) {
super(name, description);
}
@Override
public void add(OrganizationComponent component) {
members.add(component);
}
@Override
public void remove(OrganizationComponent component) {
members.remove(component);
}
@Override
public int getMemberCount() {
int count = 0;
for (OrganizationComponent member : members) {
count += member.getMemberCount();
}
return count;
}
@Override
public void display(int depth) {
String indent = " ".repeat(depth);
System.out.println(indent + "🏢 " + name + " (共 " + getMemberCount() + " 人)");
for (OrganizationComponent member : members) {
member.display(depth + 1);
}
}
}使用示例
java
public class OrganizationDemo {
public static void main(String[] args) {
// 创建员工
Employee emp1 = new Employee("张三", "高级工程师", 20000);
Employee emp2 = new Employee("李四", "中级工程师", 15000);
Employee emp3 = new Employee("王五", "初级工程师", 10000);
Employee emp4 = new Employee("赵六", "产品经理", 18000);
Employee emp5 = new Employee("钱七", "UI 设计师", 14000);
// 创建部门
Department devDept = new Department("研发部", "负责产品开发");
devDept.add(emp1);
devDept.add(emp2);
devDept.add(emp3);
Department productDept = new Department("产品部", "负责产品设计");
productDept.add(emp4);
productDept.add(emp5);
// 创建公司
Department company = new Department("科技公司", "示例公司");
company.add(devDept);
company.add(productDept);
// 显示组织架构
company.display(0);
System.out.println("\n公司总人数: " + company.getMemberCount());
}
}JDK 中的组合模式
java.awt.Container
java
// Container 可以包含 Component(包括其他 Container)
JFrame frame = new JFrame();
JPanel panel = new JPanel();
JButton button = new JButton("Click");
frame.add(panel);
panel.add(button);java.util.Map / HashMap
java
// HashMap 的 putAll 可以看作组合操作
Map<String, Object> parent = new HashMap<>();
Map<String, Object> child = new HashMap<>();
parent.put("key1", "value1");
child.put("key2", "value2");透明方式 vs 安全方式
| 特性 | 透明方式 | 安全方式 |
|---|---|---|
| 接口定义 | Component 中定义所有操作 | Component 只定义叶子和容器共有的操作 |
| 叶子实现 | 需要抛出异常 | 不需要 |
| 一致性 | 高 | 较低 |
| 安全性 | 较低 | 高 |
优缺点
优点:
- 高层调用简单,一致性好
- 符合开闭原则,新增节点容易
- 表示复杂的树形结构
缺点:
- 叶子和容器的区别变得模糊
- 新增组件类型可能需要修改抽象类
适用场景
- 需要表示对象的部分-整体层次结构
- 希望统一对待单个对象和组合对象
- 文件系统、组织架构、菜单系统等树形结构