设计模式——组合模式

组合模式 (Composite Pattern)

什么是组合模式?

组合模式是一种结构型设计模式,它允许你将对象组合成树形结构来表示"部分-整体"的层次结构。组合模式让客户端可以统一地处理单个对象和对象组合。

简单来说:组合模式就是让单个对象和组合对象具有一致的行为。

生活中的例子

想象一下:

  • 文件系统:文件和文件夹都可以被删除、复制、移动
  • 组织架构:员工和部门都可以被管理
  • 菜单系统:菜单项和子菜单都可以被点击

为什么需要组合模式?

传统方式的问题

java 复制代码
// 需要分别处理单个对象和组合对象
if (object instanceof File) {
    file.delete();
} else if (object instanceof Folder) {
    folder.delete();
    // 还需要删除文件夹中的所有文件
}

问题

  1. 代码重复:需要分别处理单个对象和组合对象
  2. 难以维护:修改一个逻辑需要修改多处代码
  3. 客户端复杂:客户端需要知道对象的类型

组合模式的优势

java 复制代码
// 统一处理单个对象和组合对象
node.delete();  // 不管是文件还是文件夹,都调用同一个方法

优势

  1. 统一处理:客户端可以统一处理单个对象和组合对象
  2. 简化代码:简化客户端代码
  3. 易于扩展:新增节点类型很容易

组合模式的结构

复制代码
┌─────────────────────┐
│    Component        │  组件接口
├─────────────────────┤
│ + operation(): void │
│ + add(): void       │
│ + remove(): void    │
│ + getChild(): Comp  │
└──────────┬──────────┘
           │ 继承
           ├──┬──────────────────┬──────────────┐
           │                    │              │
┌──────────┴──────┐  ┌───────────┴───────┐  ┌───┴────────┐
│    Leaf         │  │    Composite      │  │ ...       │
├─────────────────┤  ├───────────────────┤  ├────────────┤
│ + operation()   │  │ - children: List  │  │            │
│ + add()         │  │ + operation()     │  │            │
│ + remove()      │  │ + add()           │  │            │
│ + getChild()    │  │ + remove()        │  │            │
└─────────────────┘  │ + getChild()      │  │            │
                     └───────────────────┘  └────────────┘

代码示例

1. 定义组件接口

java 复制代码
/**
 * 文件系统节点接口
 */
public interface FileSystemNode {
    /**
     * 显示节点信息
     */
    void display();
    
    /**
     * 添加子节点
     */
    void add(FileSystemNode node);
    
    /**
     * 移除子节点
     */
    void remove(FileSystemNode node);
    
    /**
     * 获取子节点
     */
    FileSystemNode getChild(int i);
}

2. 定义叶子节点

java 复制代码
/**
 * 叶子节点:文件
 */
public class File implements FileSystemNode {
    private String name;
    private long size;
    
    public File(String name, long size) {
        this.name = name;
        this.size = size;
    }
    
    @Override
    public void display() {
        System.out.println("  文件: " + name + " (" + size + " bytes)");
    }
    
    @Override
    public void add(FileSystemNode node) {
        throw new UnsupportedOperationException("文件不能添加子节点");
    }
    
    @Override
    public void remove(FileSystemNode node) {
        throw new UnsupportedOperationException("文件不能移除子节点");
    }
    
    @Override
    public FileSystemNode getChild(int i) {
        throw new UnsupportedOperationException("文件没有子节点");
    }
}

3. 定义组合节点

java 复制代码
/**
 * 组合节点:文件夹
 */
public class Folder implements FileSystemNode {
    private String name;
    private List<FileSystemNode> children = new ArrayList<>();
    
    public Folder(String name) {
        this.name = name;
    }
    
    @Override
    public void display() {
        System.out.println("文件夹: " + name);
        for (FileSystemNode child : children) {
            child.display();
        }
    }
    
    @Override
    public void add(FileSystemNode node) {
        children.add(node);
    }
    
    @Override
    public void remove(FileSystemNode node) {
        children.remove(node);
    }
    
    @Override
    public FileSystemNode getChild(int i) {
        return children.get(i);
    }
}

4. 使用组合

java 复制代码
/**
 * 组合模式测试类
 * 演示如何使用组合模式处理树形结构
 */
public class CompositeTest {
    
    public static void main(String[] args) {
        System.out.println("=== 组合模式测试 ===\n");
        
        // 创建文件
        File file1 = new File("readme.txt", 1024);
        File file2 = new File("image.jpg", 2048);
        File file3 = new File("document.pdf", 4096);
        File file4 = new File("data.json", 512);
        
        // 创建文件夹
        Folder folder1 = new Folder("文档");
        Folder folder2 = new Folder("图片");
        Folder folder3 = new Folder("项目");
        
        // 构建文件系统树
        folder1.add(file1);
        folder1.add(file3);
        
        folder2.add(file2);
        
        folder3.add(folder1);
        folder3.add(folder2);
        folder3.add(file4);
        
        // 显示文件系统
        System.out.println("--- 文件系统结构 ---");
        folder3.display();
        
        System.out.println("\n=== 组合模式的优势 ===");
        System.out.println("1. 统一处理:客户端可以统一处理单个对象和组合对象");
        System.out.println("2. 简化代码:简化客户端代码");
        System.out.println("3. 易于扩展:新增节点类型很容易");
        System.out.println("4. 层次清晰:清晰地表示层次结构");
        
        System.out.println("\n=== 实际应用场景 ===");
        System.out.println("1. 文件系统:文件和文件夹");
        System.out.println("2. 组织架构:员工和部门");
        System.out.println("3. 菜单系统:菜单项和子菜单");
        System.out.println("4. XML/JSON解析:节点和子节点");
    }
}

组合模式的优点

  1. 统一处理:客户端可以统一处理单个对象和组合对象
  2. 简化代码:简化客户端代码
  3. 易于扩展:新增节点类型很容易
  4. 层次清晰:清晰地表示层次结构

组合模式的缺点

  1. 设计复杂:设计比较复杂
  2. 限制类型:限制了组件的类型

适用场景

  1. 树形结构:需要表示树形结构
  2. 统一处理:需要统一处理单个对象和组合对象
  3. 层次结构:需要表示部分-整体的层次结构

常见应用场景

  • 文件系统:文件和文件夹
  • 组织架构:员工和部门
  • 菜单系统:菜单项和子菜单
  • XML/JSON解析:节点和子节点

使用建议

  • 树形结构:使用组合模式
  • 统一处理:使用组合模式
  • 简单结构:直接使用即可

注意事项

⚠️ 组合模式虽然有用,但要注意:

  • 叶子节点的add和remove方法可以抛出异常
  • 考虑使用透明性或安全性模式
相关推荐
茶本无香1 天前
设计模式之六—组合模式:构建树形结构的艺术
java·设计模式·组合模式
Yu_Lijing5 天前
基于C++的《Head First设计模式》笔记——组合模式
c++·笔记·设计模式·组合模式
sxlishaobin12 天前
设计模式之组合模式
设计模式·组合模式
Engineer邓祥浩12 天前
设计模式学习(11) 23-9 组合模式
学习·设计模式·组合模式
Geoking.13 天前
【设计模式】组合模式(Composite)详解
java·设计模式·组合模式
蔺太微14 天前
组合模式(Composite Pattern)
设计模式·组合模式
会员果汁14 天前
15.设计模式-组合模式
设计模式·组合模式
仅此,1 个月前
Java请求进入Python FastAPI 后,请求体为空,参数不合法
java·spring boot·python·组合模式·fastapi
航Hang*1 个月前
Photoshop 图形与图像处理技术——第2章:图像处理基础
图像处理·笔记·ui·组合模式·photoshop