Компоновщик

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

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

Шаблон компоновщик позволяет клиентам работать с индивидуальными объектами в едином стиле.
Пример
Напишем класс, который группирует товар в посылки. Определяем базовый класс LinkerObject. Описываем метод _print, который будет вызывается в методе __str__.

Далее создаем классы и наследуем их от LinkerObject, переопределяем метод name.

Теперь можно добавлять в компоновщик другие классы, которые также являются компоновщиками

from dataclasses import dataclass


@dataclass
class LinkerObject:
    product: str = None

    def __post_init__ (self):
        self.children = []
        self._name  = 'Linker'

    @property
    def name(self) -> str:
        return self._name

    def _print(self, items, depth) -> None:
        items.append('*' * depth)
        if self.product:
            items.append(self.product)
        items.append(f'{self.name}\n')
        for child in self.children:
            child._print(items, depth + 1)

    def __str__(self) -> str:
        items = []
        self._print(items, 0)
        return ''.join(items)


class Meter(LinkerObject):
    @property
    def name(self):
        return '(метр)'


class Kilogram(LinkerObject):
    @property
    def name(self):
        return '(кг))'


if __name__ == '__main__':
    group1 = LinkerObject()
    group1._name = 'Посылка 1'
    group1.children.append(Meter('Ткань'))
    group1.children.append(Kilogram('Пуговицы'))

    group2 = LinkerObject()
    group2._name = 'Посылка в посылке'
    group2.children.append(Meter('Шнурок'))
    group2.children.append(Kilogram('Брошки'))
    group1.children.append(group2)

    print(group1)

Вывод
  • Объекты могут использовать другие объекты через наследование/композицию
  • Некоторым составным и единичным объектам требуется одинаковая обработка
  • Компоновщик позволяет обрабатывать одинаково как простые объекты, так и составные