text: # coding: utf-8
  
  """
  Компоновщик (Composite) - паттерн, структурирующий объекты.
  
  Компонует объекты в древовидные структуры для представления иерархий часть-целое.
  Позволяет клиентам единообразно трактовать индивидуальные и составные объекты.
  """
  
  from __future__ import annotations
  from abc import ABC, abstractmethod
  from typing import List
  
  
  class Component(ABC):
      """
      Базовый класс Компонент объявляет общие операции как для простых, так и для
      сложных объектов структуры.
      """
  
      @property
      def parent(self) -> Component:
          return self._parent
  
      @parent.setter
      def parent(self, parent: Component):
          """
          При необходимости базовый Компонент может объявить интерфейс для
          установки и получения родителя компонента в древовидной структуре. Он
          также может предоставить некоторую реализацию по умолчанию для этих
          методов.
          """
  
          self._parent = parent
  
      """
      В некоторых случаях целесообразно определить операции управления потомками
      прямо в базовом классе Компонент. Таким образом, вам не нужно будет
      предоставлять конкретные классы компонентов клиентскому коду, даже во время
      сборки дерева объектов. Недостаток такого подхода в том, что эти методы
      будут пустыми для компонентов уровня листа.
      """
  
      def add(self, component: Component) -> None:
          pass
  
      def remove(self, component: Component) -> None:
          pass
  
      def is_composite(self) -> bool:
          """
          Вы можете предоставить метод, который позволит клиентскому коду понять,
          может ли компонент иметь вложенные объекты.
          """
  
          return False
  
      @abstractmethod
      def operation(self) -> str:
          """
          Базовый Компонент может сам реализовать некоторое поведение по умолчанию
          или поручить это конкретным классам, объявив метод, содержащий поведение
          абстрактным.
          """
  
          pass
  
  
  class Leaf(Component):
      """
      Класс Лист представляет собой конечные объекты структуры. Лист не может
      иметь вложенных компонентов.
  
      Обычно объекты Листьев выполняют фактическую работу, тогда как объекты
      Контейнера лишь делегируют работу своим подкомпонентам.
      """
  
      def operation(self) -> str:
          return "Leaf"
  
  
  class Composite(Component):
      """
      Класс Контейнер содержит сложные компоненты, которые могут иметь вложенные
      компоненты. Обычно объекты Контейнеры делегируют фактическую работу своим
      детям, а затем «суммируют» результат.
      """
  
      def __init__(self) -> None:
          self._children: List[Component] = []
  
      """
      Объект контейнера может как добавлять компоненты в свой список вложенных
      компонентов, так и удалять их, как простые, так и сложные.
      """
  
      def add(self, component: Component) -> None:
          self._children.append(component)
          component.parent = self
  
      def remove(self, component: Component) -> None:
          self._children.remove(component)
          component.parent = None
  
      def is_composite(self) -> bool:
          return True
  
      def operation(self) -> str:
          """
          Контейнер выполняет свою основную логику особым образом. Он проходит
          рекурсивно через всех своих детей, собирая и суммируя их результаты.
          Поскольку потомки контейнера передают эти вызовы своим потомкам и так
          далее, в результате обходится всё дерево объектов.
          """
  
          results = []
          for child in self._children:
              results.append(child.operation())
          return f"Branch({'+'.join(results)})"
  
  
  def client_code(component: Component) -> None:
      """
      Клиентский код работает со всеми компонентами через базовый интерфейс.
      """
  
      print(f"RESULT: {component.operation()}", end="")
  
  
  def client_code2(component1: Component, component2: Component) -> None:
      """
      Благодаря тому, что операции управления потомками объявлены в базовом классе
      Компонента, клиентский код может работать как с простыми, так и со сложными
      компонентами, вне зависимости от их конкретных классов.
      """
  
      if component1.is_composite():
          component1.add(component2)
  
      print(f"RESULT: {component1.operation()}", end="")
  
  
  if __name__ == "__main__":
      # Таким образом, клиентский код может поддерживать простые компоненты-
      # листья...
      simple = Leaf()
      print("Client: I've got a simple component:")
      client_code(simple)
      print("\n")
  
      # ...а также сложные контейнеры.
      tree = Composite()
  
      branch1 = Composite()
      branch1.add(Leaf())
      branch1.add(Leaf())
  
      branch2 = Composite()
      branch2.add(Leaf())
  
      tree.add(branch1)
      tree.add(branch2)
  
      print("Client: Now I've got a composite tree:")
      client_code(tree)
      print("\n")
  
      print(
          "Client: I don't need to check the components classes even when managing the tree:"
      )
      client_code2(tree, simple)
  
      # -------------------------------------------------------------------------------
      # Результат выполнения
      # -------------------------------------------------------------------------------
      """
      Client: I've got a simple component:
      RESULT: Leaf
  
      Client: Now I've got a composite tree:
      RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf))
  
      Client: I don't need to check the components classes even when managing the tree:
      RESULT: Branch(Branch(Leaf+Leaf)+Branch(Leaf)+Leaf)
      """
  