«1. Введение

В этом кратком руководстве мы познакомимся с шаблоном составного проектирования в Java.

Мы собираемся описать структуру и цель ее использования.

2. Структура

Составной шаблон предназначен для того, чтобы можно было одинаково обращаться с отдельными объектами и композициями объектов или «композитами».

Его можно рассматривать как древовидную структуру, состоящую из типов, наследующих базовый тип, и он может представлять собой одну часть или целую иерархию объектов.

Мы можем разбить шаблон на:

    компонент — это базовый интерфейс для всех объектов в композиции. Это должен быть либо интерфейс, либо абстрактный класс с общими методами для управления дочерними композитами. leaf — реализует поведение базового компонента по умолчанию. Он не содержит ссылки на другие объекты. составной – имеет листовые элементы. Он реализует методы базового компонента и определяет дочерние операции. клиент — имеет доступ к элементам композиции, используя объект базового компонента.

3. Практический пример

Теперь давайте углубимся в реализацию. Предположим, мы хотим построить иерархическую структуру отделов в компании.

3.1. Базовый компонент

В качестве объекта компонента мы определим простой интерфейс отдела:

public interface Department {
    void printDepartmentName();
}

3.2. Листовые компоненты

Для конечных компонентов определим классы для финансового отдела и отдела продаж:

public class FinancialDepartment implements Department {

    private Integer id;
    private String name;

    public void printDepartmentName() {
        System.out.println(getClass().getSimpleName());
    }

    // standard constructor, getters, setters
}

Второй конечный класс, SalesDepartment, подобен:

public class SalesDepartment implements Department {

    private Integer id;
    private String name;

    public void printDepartmentName() {
        System.out.println(getClass().getSimpleName());
    }

    // standard constructor, getters, setters
}

Оба класса реализуют метод printDepartmentName() из базовый компонент, где они печатают имена классов для каждого из них.

Кроме того, поскольку они являются конечными классами, они не содержат других объектов отдела.

Далее давайте также рассмотрим составной класс.

3.3. Составной элемент

В качестве составного класса создадим класс HeadDepartment:

public class HeadDepartment implements Department {
    private Integer id;
    private String name;

    private List<Department> childDepartments;

    public HeadDepartment(Integer id, String name) {
        this.id = id;
        this.name = name;
        this.childDepartments = new ArrayList<>();
    }

    public void printDepartmentName() {
        childDepartments.forEach(Department::printDepartmentName);
    }

    public void addDepartment(Department department) {
        childDepartments.add(department);
    }

    public void removeDepartment(Department department) {
        childDepartments.remove(department);
    }
}

Это составной класс, поскольку он содержит набор компонентов отдела, а также методы для добавления и удаления элементов из списка.

Составной метод printDepartmentName() реализован путем перебора списка листовых элементов и вызова соответствующего метода для каждого из них.

4. Тестирование

В целях тестирования рассмотрим класс CompositeDemo:

public class CompositeDemo {
    public static void main(String args[]) {
        Department salesDepartment = new SalesDepartment(
          1, "Sales department");
        Department financialDepartment = new FinancialDepartment(
          2, "Financial department");

        HeadDepartment headDepartment = new HeadDepartment(
          3, "Head department");

        headDepartment.addDepartment(salesDepartment);
        headDepartment.addDepartment(financialDepartment);

        headDepartment.printDepartmentName();
    }
}

Сначала мы создадим два экземпляра для финансового отдела и отдела продаж. После этого мы создаем головной отдел и добавляем к нему ранее созданные экземпляры.

Наконец, мы можем протестировать метод композиции printDepartmentName(). Как и ожидалось, выходные данные содержат имена классов каждого листового компонента:

SalesDepartment
FinancialDepartment

5. Заключение

В этой статье мы узнали о шаблоне проектирования Composite. В описании подчеркивается основная структура и демонстрируется использование на практическом примере.

Как обычно, полный код доступен в проекте Github.