Компоновщик(Composite)

Компоновщик(Composite)

KarmanovichDev

Определение из wiki:

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

При таком обращении, удаётся скрыть сложность реализации, так как клиент знает только о том объекте с которым взаимодействует.


Преимущества паттерна:

  • Упрощает работу клиента со сложным деревом компонентов
  • Упрощает добавление новых видов компонентов(клиенту не обязательно знать с какими видами компонентов он работает)


Примеры из жизни:

  1. Посылка - в коробке могут лежать другие коробки в которых в свою очередь могут лежать как коробки поменьше, так и конкретные товары.
  2. Структура большинства компании начинается с руководителя, заканчивается линейными специалистами и выстраивается в древовидную структуру.
  3. Файловая система на вашем ПК представляет из себя структуру вида дерево, где конечными(листовыми) узлами являются файлы(ну или пустые папки).


Схема паттерна(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. Этот менеджер смог бы возвращать клиентскому коду уже собранные структуры(быть фабрикой для этих структур) в рамках компании: отдельный сотрудник, отдел, группу отделов, филиал, вся компания. После этого клиент проводил бы с ними манипуляции не заботясь о внутренней сложности структуры(так как интерфейс взаимодействия один).


Это был базовый обзор паттерна компоновщик. В дальнейшем я напишу вторую часть где будет:

  1. Боевой пример с тестами
  2. Пример компоновщика, где созданием объектов занимается строитель
  3. Пример компоновщика и итератор который может собирать информацию о компании в нужном разрезе

Report Page