Компоновщик(Composite)
KarmanovichDevОпределение из wiki:
Компоновщик - структурный шаблон проектирования, объединяющий объекты в древовидную структуру для представления иерархии от частного к целому. Компоновщик позволяет клиентам обращаться к отдельным объектам и к группам объектов одинаково.
При таком обращении, удаётся скрыть сложность реализации, так как клиент знает только о том объекте с которым взаимодействует.
Преимущества паттерна:
- Упрощает работу клиента со сложным деревом компонентов
- Упрощает добавление новых видов компонентов(клиенту не обязательно знать с какими видами компонентов он работает)
Примеры из жизни:
- Посылка - в коробке могут лежать другие коробки в которых в свою очередь могут лежать как коробки поменьше, так и конкретные товары.
- Структура большинства компании начинается с руководителя, заканчивается линейными специалистами и выстраивается в древовидную структуру.
- Файловая система на вашем ПК представляет из себя структуру вида дерево, где конечными(листовыми) узлами являются файлы(ну или пустые папки).
Схема паттерна(UML):

- ConditionList и ConditionLeaf оба наследуются от класса Condition
- ConditionList может содержать внутри себя любое кол-во как ConditionLeaf, так и ConditionList, которые в свою очередь так же могут содержать внутри себя другие объекты типа Condition.
- ConditionLeaf - Сам отвечает на вопрос - "прошёл ли переданный продукт проверку?".
- ConditionList - Делегирует проверку своим components, но может дополнительно добавить и свою.
Из ConditionList и ConditionLeaf в данном случае и будут строиться древовидные структуры объектов. Так как у них одинаковый интерфейс взаимодействия, и ответственность за обработку поддерева любого размера лежит на самих классах Condition. Клиентский код работает с объектом любой вложенности как с единичным.

Давайте разберём пример кода с использованием паттерна компоновщик:

- CompanyCostEntity - Любые человеко-затраты компании. Завтра мы легко можем создать класс BranchEmployees со своей логикой создания, и так же следить за тем, в какие расходы компании обходится её филиалы или дочерние компании.
- Employee, GroupEmployees это текущие виды CompanyCostEntity, из которых будет строиться древовидная структура компании.
- Все CompanyCostEntity имеют единый интерфейс def cost(), но все реализуют его по-разному. Листовой узел структуры Employee просто возвращает свою цену в то время как GroupEmployees к своей цене добавляет стоимость каждого дочернего элемента.
Пример создания структуры продуктовой команды:

На деле ваши объекты могут иметь больший функционал чем сейчас, и ещё один уровень абстракции, что-то вроде EmployeesManager. Этот менеджер смог бы возвращать клиентскому коду уже собранные структуры(быть фабрикой для этих структур) в рамках компании: отдельный сотрудник, отдел, группу отделов, филиал, вся компания. После этого клиент проводил бы с ними манипуляции не заботясь о внутренней сложности структуры(так как интерфейс взаимодействия один).
Это был базовый обзор паттерна компоновщик. В дальнейшем я напишу вторую часть где будет:
- Боевой пример с тестами
- Пример компоновщика, где созданием объектов занимается строитель
- Пример компоновщика и итератор который может собирать информацию о компании в нужном разрезе