# 组合模式

# 概念

组合模式(Composite Pattern)是一种结构型设计模式,它将对象组合成树形结构以表示"部分-整体"的层次结构。该模式允许用户以统一的方式处理单个对象和组合对象,简化了客户端代码并增强了系统的灵活性。

# 作用

1.统一处理方式:用户可以用相同的方式处理单个对象和组合对象,无需区分。

2.简化客户端代码:客户端只需与顶层组件交互,无需关心内部复杂结构。

3.灵活构建层次结构:可以动态添加或删除组件,构建复杂的树形结构。

4.增强扩展性:新增组件类型时无需修改现有代码,符合开闭原则。

# 场景

1.表示对象的部分-整体层次结构:如文件系统(文件/文件夹)、组织架构(员工/部门)。

2.需要统一处理简单元素和复杂元素:如GUI组件(按钮/面板)、菜单系统。

3.处理树形数据结构:如XML/JSON解析、目录树展示。

4.需要递归组合的场景:如数学表达式(操作数/运算符)。

# 举例

以下是使用组合模式实现公司员工层级关系的Java代码示例:

// 组件接口(Component),所有对象(树枝和叶子)都实现这个接口
interface EmployeeComponent {
    void add(EmployeeComponent employee);
    void remove(EmployeeComponent employee);
    void display();
}
// 叶子节点(Leaf)
class Employee implements EmployeeComponent {
    private String name;
    private String position;

    public Employee(String name, String position) {
        this.name = name;
        this.position = position;
    }

    // 因为叶子节点不能添加子节点,所以这里要报错
    @Override
    public void add(EmployeeComponent employee) {
        throw new UnsupportedOperationException("Cannot add to a leaf node.");
    }

    // 同上
    @Override
    public void remove(EmployeeComponent employee) {
        throw new UnsupportedOperationException("Cannot remove from a leaf node.");
    }

    @Override
    public void display() {
        System.out.println("Employee: " + name + " (" + position + ")");
    }
}
// 容器节点(Composite)
class Department implements EmployeeComponent {
    private String name;
    private List<EmployeeComponent> employees = new ArrayList<>();

    public Department(String name) {
        this.name = name;
    }

    @Override
    public void add(EmployeeComponent employee) {
        employees.add(employee);
    }

    @Override
    public void remove(EmployeeComponent employee) {
        employees.remove(employee);
    }

    @Override
    public void display() {
        System.out.println("Department: " + name);
        for (EmployeeComponent employee : employees) {
            employee.display();
        }
    }
}

控制台输出:

// 客户端代码
public class Main {
    public static void main(String[] args) {
        Department hrDepartment = new Department("Human Resources");
        hrDepartment.add(new Employee("Alice", "HR Manager"));
        hrDepartment.add(new Employee("Bob", "Recruiter"));

        Department itDepartment = new Department("Information Technology");
        itDepartment.add(new Employee("Charlie", "IT Manager"));
        itDepartment.add(new Employee("Diana", "Software Engineer"));

        Department company = new Department("Company");
        company.add(hrDepartment);
        company.add(itDepartment);

        company.display();
    }
}

# 反例

如果不使用组合模式,我们需要为单个员工和部门分别处理,导致代码重复且难以维护整体结构:

class Employee {
    private String name;
    private String position;

    public Employee(String name, String position) {
        this.name = name;
        this.position = position;
    }

    public void display() {
        System.out.println("Employee: " + name + " (" + position + ")");
    }
}
class Department {
    private String name;
    private List<Employee> employees = new ArrayList<>();

    public Department(String name) {
        this.name = name;
    }

    public void addEmployee(Employee employee) {
        employees.add(employee);
    }

    public void removeEmployee(Employee employee) {
        employees.remove(employee);
    }

    public void display() {
        System.out.println("Department: " + name);
        for (Employee employee : employees) {
            employee.display();
        }
    }
}
public class Main {
    public static void main(String[] args) {
        Employee alice = new Employee("Alice", "HR Manager");
        Employee bob = new Employee("Bob", "Recruiter");
        Department hrDepartment = new Department("Human Resources");
        hrDepartment.addEmployee(alice);
        hrDepartment.addEmployee(bob);

        Employee charlie = new Employee("Charlie", "IT Manager");
        Employee diana = new Employee("Diana", "Software Engineer");
        Department itDepartment = new Department("Information Technology");
        itDepartment.addEmployee(charlie);
        itDepartment.addEmployee(diana);

        System.out.println("HR Department:");
        hrDepartment.display();

        System.out.println("\nIT Department:");
        itDepartment.display();
    }
}

# 原理

组合模式包含四个核心组成部分:

1.组件(Component):定义组合中所有对象的通用接口,声明用于访问和管理子组件的方法(如add/remove/display)。可以是接口或抽象类。

2.叶子节点(Leaf):表示组合中的基本元素(如员工),没有子节点。实现组件接口的操作方法,但子组件管理方法需抛出异常或空实现。

3.容器节点(Composite):表示包含子组件的复合元素(如部门)。实现组件接口的所有方法,内部维护子组件集合,并将操作委托给子组件。

4.客户端(Client):通过组件接口与组合结构交互,无需区分叶子节点和容器节点,统一处理所有组件。

# 特点

# 优点

1.可以方便地将对象组合成树形结构,表示"部分-整体"的层次关系。

2.单个对象和组合对象具有相同的接口,用户可以以统一的方式处理它们。

3.增加新的组件类变得容易。

# 缺点

1.可能会导致设计中出现过多的抽象类或接口,从而增加系统的复杂性。

2.可能会使得系统的行为变得难以预测,因为用户可以以任何方式组合对象。

总结

组合模式通过树形结构统一处理单个对象与组合对象,简化了客户端代码并增强了系统扩展性。它适用于表示部分-整体层次结构,如组织架构、文件系统等场景,但需注意避免过度设计带来的复杂性。



微信公众号

QQ交流群
原创网站开发,偏差难以避免。

如若发现错误,诚心感谢反馈。

愿你倾心相念,愿你学有所成。

愿你朝华相顾,愿你前程似锦。