Объединяет объекты в древовидную структуру для представления иерархии от частного к целому. Компоновщик позволяет клиентам обращаться к отдельным объектам и к группам объектов одинаково.
Лист - это простой элемент дерева, не имеющий ответвлений.
Контейнер (или «композит» или узел) - это составной элемент дерева. Он содержит набор дочерних компонентов, но ничего не знает об их типах. Это могут быть как простые компоненты-листья, так и другие компоненты-контейнеры. Но это не является проблемой, так как все дочерние элементы следуют общему интерфейсу.
-
Когда вам нужно представить древовидную структуру объектов.
- Паттерн Компоновщик предлагает хранить в составных объектах ссылки на другие простые или составные объекты. Те, в свою очередь, тоже могут хранить свои вложенные объекты и так далее. В итоге вы можете строить сложную древовидную структуру данных, используя всего две основные разновидности объектов.
-
Когда клиенты должны единообразно трактовать простые и составные объекты.
- Благодаря тому, что простые и составные объекты реализуют общий интерфейс, клиенту безразлично с каким именно объектом ему предстоит работать.
-
Убедитесь, что вашу бизнес-логику можно представить как древовидную структуру. Попытайтесь разбить её на простые элементы и контейнеры. Помните, что контейнеры могут содержать как простые элементы, так и другие контейнеры.
-
Создайте общий интерфейс компонентов, который объединит операции контейнеров и простых элементов дерева. Интерфейс будет удачным, если вы сможете взаимозаменять простые и составные компоненты без потери смысла.
-
Создайте класс компонентов-листьев, не имеющих дальнейших ответвлений. Имейте в виду, что программа может содержать несколько видов таких классов.
-
Создайте класс компонентов-контейнеров, и добавьте в него массив для хранения ссылок на вложенные компоненты. Этот массив должен быть способен содержать как простые, так и составные компоненты, поэтому убедитесь, что он объявлен с типом интерфейса компонентов.
Реализуйте в контейнере методы интерфейса компонентов, помня о том, что контейнеры должны делегировать основную работу своим дочерним компонентам.
-
Добавьте операции добавления и удаления дочерних элементов в класс контейнеров.
(Ex) Имейте в виду, что методы добавления/удаления дочерних элементов можно поместить и в интерфейс компонентов. Да, это нарушит принцип разделения интерфейса, так как реализации методов будут пустыми в компонентах-листьях. Но зато все компоненты дерева станут действительно одинаковыми для клиента.
+ | - |
---|---|
Упрощает архитектуру клиента при работе со сложным деревом компонентов. | Создаёт слишком общий дизайн классов. |
Облегчает добавление новых видов компонентов. |
-
Строитель позволяет пошагово сооружать дерево Компоновщика.
-
Цепочку обязанностей часто используют вместе с Компоновщиком. В этом случае, запрос передаётся от дочерних компонентов к их родителям.
-
(Ex)Вы можете обходить дерево Компоновщика, используя Итератор.
-
Вы можете выполнить какое-то действие над всем деревом Компоновщика при помощи Посетителя.
-
Компоновщик часто совмещают с Легковесом, чтобы реализовать общие ветки дерева и сэкономить при этом память.
-
Компоновщик и Декоратор имеют похожие структуры классов из-за того, что оба построены на рекурсивной вложенности. Она позволяет связать в одну структуру бесконечное количество объектов.
Декоратор оборачивает только один объект, а узел Компоновщика может иметь много детей. Декоратор добавляет вложенному объекту новую функциональность, а Компоновщик не добавляет ничего нового, но «суммирует» результаты всех своих детей.
Но они могут и сотрудничать: Компоновщик может использовать Декоратор, чтобы переопределить функции отдельных частей дерева компонентов.
-
Архитектура, построенная на Компоновщиках и Декораторах, часто может быть улучшена за счёт внедрения Прототипа. Он позволяет клонировать сложные структуры объектов, а не собирать их заново.