# 组合模式(Composite Pattern)

目录: https://note.dolyw.com/design/ (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
--尾声
上次更新时间: 2023-12-15 03:14:55