组合模式(Composite Pattern)的定义:
组合模式是指将对象组合成树形结构以表示“部分-整体”的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性。
它这个名字挺有歧义的,我理解的组合是将各种不同元素组成一个整体,它这个好像不是这个意思。
还不如叫组合成树状结构模式 更贴合!
核心思想
- 统一接口: 定义一个接口,所有组件(无论是叶子还是组合)都实现这个接口。
 - 递归组合: 组合对象可以包含多个子对象,这些子对象也可以是组合对象或叶子对象。
 
组件类型
- 叶子节点: 最小的基本对象,没有子对象。
 - 组合节点: 容器对象,可以包含叶子或其他组合。
 
工作原理
- 定义组件接口: 包含所有子类需要实现的方法。
 - 实现叶子类: 实现组件接口的方法,执行具体操作。
 - 实现组合类: 包含子组件的列表,实现接口方法,并在这些方法中递归调用子组件的方法。
 
适用场景
- 希望客户端能以统一的方式处理单个对象和组合对象。
 - 需要表示对象的部分-整体层次结构。
 
优点
- 简化客户端代码,不再需要关心处理的是单个对象还是组合对象。
 - 更容易添加新类型的组件。
 
缺点
- 可能使设计更加复杂。
 - 不容易限制组合中的组件类型。
 
示例
文件系统中,文件和文件夹就是组合模式的典型例子。文件夹可以包含文件或其他文件夹,客户端可以用相同的方式处理文件和文件夹。
应用场景
- 系统的文件处理系统
 - UI界面的Menu item
 - 公司人员职级划分
 - ...
 
What is Composite Pattern
Composite Pattern(组合模式)也叫叉数、对象树、Object Tree、...。它的思想很类似自然界的树状结构。组合模式也是用于描述具有层次结构的数据。

树状结构很有意思的地方在于,每个树枝都是一样的,甚至树叶和树枝都是一样的,区别只是在于树叶下面没有树叶了。
组合模式就是借鉴了这个思想,它允许将对象组合成树状结构,并以统一的方式处理对象及对象组合。组合模式使得客户端可以一致地对待单个对象和对象组合,无需区分它们的差异。
关键要素
- leaf and branch interface
 - leaf
 - branch
 - Client
 
Example —— 读取文件夹和文件
假设我们要设计一个文件系统的结构,包括文件和文件夹。文件夹可以包含文件和其他文件夹,而文件没有子组件。我们可以使用组合模式来实现这个文件系统结构。
leaf and branch interface
public interface FileSystemComponent {
    void showInfo();
}
leaf and folder
public class File implements FileSystemComponent {
    private String name;
    
    public File(String name) {
        this.name = name;
    }
    
    public void showInfo() {
        System.out.println("File: " + name);
    }
}
public class Folder implements FileSystemComponent {
    private String name;
    private List<FileSystemComponent> components;
    
    public Folder(String name) {
        this.name = name;
        this.components = new ArrayList<>();
    }
    
    public void addComponent(FileSystemComponent component) {
        components.add(component);
    }
    
    public void removeComponent(FileSystemComponent component) {
        components.remove(component);
    }
    
    public void showInfo() {
        System.out.println("Folder: " + name);
        for (FileSystemComponent component : components) {
            component.showInfo();
        }
    }
}
Client
public class Client {
    public static void main(String[] args) {
        // 创建文件和文件夹
        FileSystemComponent file1 = new File("file1.txt");
        FileSystemComponent file2 = new File("file2.doc");
        
        Folder folder1 = new Folder("Folder 1");
        Folder folder2 = new Folder("Folder 2");
        
        // 组合文件和文件夹
        folder1.addComponent(file1);
        folder1.addComponent(file2);
        folder1.addComponent(folder2);
        
        // 显示文件系统结构
        folder1.showInfo();
    }
}
out :
Folder: Folder 1
File: file1.txt
File: file2.doc
Folder: Folder 2
通过组合模式,我们可以将文件和文件夹组织成树状结构,使用统一的方式处理它们。
客户端可以递归地遍历文件系统的组件,无需关心是单个文件还是文件夹。这样,组合模式提供了一种灵活且可扩展的方式来处理对象的组合关系。
Example —— 统计城市人口数
这个案例并不是那么恰当!
interface
public interface Counter {
    int count();
}
leaf
public class Leaf implements Counter {
    private int sum = 0;
    public Leaf(int sum) {
        this.sum = sum;
    }
    @Override
    public int count() {
        return sum;
    }
}
Branch
public class Branch implements Counter {
    private List<Counter> counterList = new ArrayList<>();
    public void add(Counter counter) {
        counterList.add(counter);
    }
    public void delete(Counter counter) {
        counterList.remove(counter);
    }
    public List<Counter> getChild() {
        return counterList;
    }
    @Override
    public int count() {
        int sum = 0;
        for (Counter counter : counterList) {
            sum += counter.count();
        }
        return sum;
    }
}
Client
    /**
     * 需求是做一个统计全国人口数量的功能
     * 全国根据地区划分就是一个树状结构
     * ------------------------------
     * 国家
     *   城市1
     *     区1
     *     区2
     *   城市2
     *     区1
     *     区2
     * ------------------------------
     */
    public static void main(String[] args) {
        System.out.println("开始统计人数");
        Branch city = new Branch(); // 模拟市
        Leaf beijing = new Leaf(100);
        Leaf shanghai = new Leaf(200);
        city.add(beijing);
        city.add(shanghai);
        Branch district = new Branch(); // 模拟区
        Leaf dongcheng = new Leaf(300);
        Leaf xicheng = new Leaf(400);
        district.add(dongcheng);
        district.add(xicheng);
        city.add(district);  // 区加入城市
        System.out.println(city.count()); //1000
    }
                    
                
                
            
        
浙公网安备 33010602011771号