# 组合模式(Composite Pattern)
代码地址
- Github:DesignPattern/src/main/java/com/design/composite (opens new window)
 - Gitee(码云):DesignPattern/src/main/java/com/design/composite (opens new window)
 
# 1. 介绍
组合模式,又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构,其实就是类似树的应用
# 1.1. 特点
待补充
# 1.2. 结构
待补充
# 1.3. 优缺点
- 意图:将对象组合成树形结构以表示"部分-整体"的层次结构。组合模式使得用户对单个对象和组合对象的使用具有一致性
 - 主要解决:它在我们树型结构的问题中,模糊了简单元素和复杂元素的概念,客户程序可以像处理简单元素一样来处理复杂元素,从而使得客户程序与复杂元素的内部结构解耦
 - 何时使用:
- 您想表示对象的部分-整体层次结构(处理树形结构数据)
 - 您希望用户忽略组合对象与单个对象的不同,用户将统一地使用组合结构中的所有对象
 
 - 如何解决:树枝和叶子实现统一接口,树枝内部组合该接口
 - 关键代码:树枝内部组合该接口,并且含有内部属性 List,里面放 Component
 - 注意事项:定义时为具体类
 
- 优点:
- 高层模块调用简单
 - 节点自由增加,符合开闭原则
 
 - 缺点:
- 在使用组合模式时,其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则
 - 树形处理较为复杂
 
 - 应用场景
- 树形菜单,文件、文件夹的管理
 
 
# 2. 代码
两个示例
# 2.1. 员工示例
/**
 * 创建 Employee 类,该类带有 Employee 对象的列表
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/1/31 14:07
 */
public class Employee {
    private String name;
    private String dept;
    private int salary;
    private List<Employee> subordinates;
    public Employee(String name, String dept, int sal) {
        this.name = name;
        this.dept = dept;
        this.salary = sal;
        subordinates = new ArrayList<>();
    }
    public void add(Employee e) {
        subordinates.add(e);
    }
    public void remove(Employee e) {
        subordinates.remove(e);
    }
    public List<Employee> getSubordinates() {
        return subordinates;
    }
    public String toString() {
        return ("Employee :[ Name : " + name
                + ", dept : " + dept + ", salary :"
                + salary + " ]");
    }
}
/**
 * 组合模式
 *
 * 使用 Employee 类来创建和打印员工的树形层次结构
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/1/31 14:07
 */
public class Main {
    public static void main(String[] args) {
        Employee Ceo = new Employee("王明", "CEO", 30000);
        Employee headSales = new Employee("销售主管", "销售部门", 20000);
        Employee headMarketing = new Employee("营销主管", "营销部门", 20000);
        Employee clerk1 = new Employee("文员1", "营销部门", 10000);
        Employee clerk2 = new Employee("文员2", "营销部门", 10000);
        Employee sales1 = new Employee("销售1", "销售部门", 10000);
        Employee sales2 = new Employee("销售2", "销售部门", 10000);
        Ceo.add(headSales);
        Ceo.add(headMarketing);
        headSales.add(sales1);
        headSales.add(sales2);
        headMarketing.add(clerk1);
        headMarketing.add(clerk2);
        // 打印该组织的所有员工
        System.out.println(Ceo);
        for (Employee headEmployee : Ceo.getSubordinates()) {
            System.out.println(headEmployee);
            for (Employee employee : headEmployee.getSubordinates()) {
                System.out.println(employee);
            }
        }
    }
}
Employee :[ Name : 王明, dept : CEO, salary :30000 ]
Employee :[ Name : 销售主管, dept : 销售部门, salary :20000 ]
Employee :[ Name : 销售1, dept : 销售部门, salary :10000 ]
Employee :[ Name : 销售2, dept : 销售部门, salary :10000 ]
Employee :[ Name : 营销主管, dept : 营销部门, salary :20000 ]
Employee :[ Name : 文员1, dept : 营销部门, salary :10000 ]
Employee :[ Name : 文员2, dept : 营销部门, salary :10000 ]
# 2.2. 节点示例
/**
 * 节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/1/31 14:15
 */
abstract public class Node {
    abstract public void p();
}
/**
 * 叶子节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/1/31 14:15
 */
public class LeafNode extends Node {
    String content;
    public LeafNode(String content) {
        this.content = content;
    }
    @Override
    public void p() {
        System.out.println(content);
    }
}
/**
 * 分支节点
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/1/31 14:15
 */
class BranchNode extends Node {
    List<Node> nodes = new ArrayList<>();
    String name;
    public BranchNode(String name) {
        this.name = name;
    }
    @Override
    public void p() {
        System.out.println(name);
    }
    public void add(Node n) {
        nodes.add(n);
    }
}
/**
 * 组合模式
 *
 * 模拟树形层次结构输出
 *
 * @author wliduo[i@dolyw.com]
 * @date 2023/1/31 14:07
 */
public class Main {
    public static void main(String[] args) {
        BranchNode root = new BranchNode("章节");
        BranchNode chapter1 = new BranchNode("章节1");
        BranchNode chapter2 = new BranchNode("章节2");
        Node r1 = new LeafNode("尾声");
        Node c11 = new LeafNode("小结1-1");
        Node c12 = new LeafNode("小结1-2");
        BranchNode b21 = new BranchNode("选读1");
        Node c211 = new LeafNode("选读1小结1");
        Node c212 = new LeafNode("选读1小结2");
        root.add(chapter1);
        root.add(chapter2);
        root.add(r1);
        chapter1.add(c11);
        chapter1.add(c12);
        chapter2.add(b21);
        b21.add(c211);
        b21.add(c212);
        tree(root, 0);
    }
    public static void tree(Node b, int depth) {
        for (int i = 0; i < depth; i++) {
            System.out.print("--");
        }
        b.p();
        if (b instanceof BranchNode) {
            for (Node n : ((BranchNode) b).nodes) {
                tree(n, depth + 1);
            }
        }
    }
}
章节
--章节1
----小结1-1
----小结1-2
--章节2
----选读1
------选读1小结1
------选读1小结2
--尾声