组合模式表示 “允许客户端以统一的方式处理对象,这些对象可能表示对象的层次结构”

组合设计模式的优点

  • 它定义了包含原始对象和复杂对象的类层次结构。
  • 它使添加新类型的组件更加容易。
  • 它提供了具有可管理的类或接口的结构灵活性。

组合模式的使用

适用于以下情况:

  • 当你想表示对象的完整或部分层次结构时。
  • 当需要动态添加职责到个别对象而不影响其他对象时。对象的职责可能会随时间而变化。

组合模式的 UML

3-1.jpg

组合模式的元素:

我们来看一下组合模式的4个元素。

1) 组件(Component)
  • 声明组合中对象的接口。
  • 为所有类的通用接口实现默认行为(如果适用)。
  • 声明访问和管理子组件的接口。
2) 叶子(Leaf)
  • 表示组合中的叶对象。叶子没有子对象。
  • 为组合中的原始对象定义行为。
3) 组合(Composite)
  • 定义有子对象的组件的行为。
  • 存储子组件。
  • 在组件接口中实现与子相关的操作。
4) 客户端(Client)
  • 通过组件接口操作组合中的对象。

注意:上面通用 UML 的工作流程如下。

客户端使用组件类接口与组合结构中的对象进行交互。如果接收者是叶子节点,则请求将直接处理。如果接收者是组合节点,则通常会将请求转发给其子节点以执行附加操作。

组合模式示例

我们可以通过下面给出的 UML 图轻松理解组合设计模式的示例:

3-2.jpg

实现上述 UML:

步骤 1

创建一个 Employee 接口,将其视为 组件(Component)

// 这是 Employee 接口,即组件。
public interface Employee {
    public int getId();
    public String getName();
    public double getSalary();
    public void print();
    public void add(Employee employee);
    public void remove(Employee employee);
    public Employee getChild(int i);
}
// 组件接口结束。

步骤 2

创建一个 BankManager 类,将其视为 组合(Composite) 并实现 Employee 接口。

文件:BankManager.java

// 这是 BankManager 类,即组合。
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

public class BankManager implements Employee {
    private int id;
    private String name;
    private double salary;

    public BankManager(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    List<Employee> employees = new ArrayList<Employee>();

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

    @Override
    public Employee getChild(int i) {
        return employees.get(i);
    }

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

    @Override
    public int getId() {
        return id;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getSalary() {
        return salary;
    }

    @Override
    public void print() {
        System.out.println("==========================");
        System.out.println("Id = " + getId());
        System.out.println("Name = " + getName());
        System.out.println("Salary = " + getSalary());
        System.out.println("==========================");

        Iterator<Employee> it = employees.iterator();

        while (it.hasNext()) {
            Employee employee = it.next();
            employee.print();
        }
    }
}
// BankManager 类结束。

步骤 3

创建一个 Cashier 类,将其视为 叶子(Leaf) 并实现 Employee 接口。

文件:Cashier.java

public class Cashier implements Employee {
    /* 
        在此类中,有许多方法不适用于 Cashier,因为
        它是叶节点。
    */
    private int id;
    private String name;
    private double salary;

    public Cashier(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    @Override
    public void add(Employee employee) {
        // 这是叶节点,因此此方法不适用于此类。
    }

    @Override
    public Employee getChild(int i) {
        // 这是叶节点,因此此方法不适用于此类。
        return null;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getSalary() {
        return salary;
    }

    @Override
    public void print() {
        System.out.println("==========================");
        System.out.println("Id = " + getId());
        System.out.println("Name = " + getName());
        System.out.println("Salary = " + getSalary());
        System.out.println("==========================");
    }

    @Override
    public void remove(Employee employee) {
        // 这是叶节点,因此此方法不适用于此类。
    }
}

步骤 4

创建一个 Accountant 类,也将其视为 叶子(Leaf) 并实现 Employee 接口。

文件:Accountant.java

public class Accountant implements Employee {
    /* 
        在此类中,有许多方法不适用于 Accountant,因为
        它是叶节点。
    */
    private int id;
    private String name;
    private double salary;

    public Accountant(int id, String name, double salary) {
        this.id = id;
        this.name = name;
        this.salary = salary;
    }

    @Override
    public void add(Employee employee) {
        // 这是叶节点,因此此方法不适用于此类。
    }

    @Override
    public Employee getChild(int i) {
        // 这是叶节点,因此此方法不适用于此类。
        return null;
    }

    @Override
    public int getId() {
        return id;
    }

    @Override
    public String getName() {
        return name;
    }

    @Override
    public double getSalary() {
        return salary;
    }

    @Override
    public void print() {
        System.out.println("=========================");
        System.out.println("Id = " + getId());
        System.out.println("Name = " + getName());
        System.out.println("Salary = " + getSalary());
        System.out.println("=========================");
    }

    @Override
    public void remove(Employee employee) {
        // 这是叶节点,因此此方法不适用于此类。
    }
}

步骤 5

创建一个 CompositePatternDemo 类,将其视为 客户端(Client) 并使用 Employee 接口。

文件:CompositePatternDemo.java

public class CompositePatternDemo {
    public static void main(String args[]) {
        Employee emp1 = new Cashier(101, "Sohan Kumar", 20000.0);
        Employee emp2 = new Cashier(102, "Mohan Kumar", 25000.0);
        Employee emp3 = new Accountant(103, "Seema Mahiwal", 30000.0);
        Employee manager1 = new BankManager(100, "Ashwani Rajput", 100000.0);

        manager1.add(emp1);
        manager1.add(emp2);
        manager1.add(emp3);
        manager1.print();
    }
}

输出

==========================
Id = 100
Name = Ashwani Rajput
Salary = 100000.0
==========================
==========================
Id = 101
Name = Sohan Kumar
Salary = 20000.0
==========================
==========================
Id = 102
Name = Mohan Kumar
Salary = 25000.0
==========================
=========================
Id = 103
Name = Seema Mahiwal
Salary = 30000.0
=========================

标签: Design Patterns, Design Patterns教程, 设计模式, 软件设计, 结构型模式, 行为型模式, 单例模式, 工厂模式, 观察者模式, 中介者模式, 访问者模式