Как реализовать паттерн "Шаблонный метод" с использованием наследования?

Паттерн "Шаблонный метод" с наследованием в Python реализуется путем создания абстрактного базового класса, который определяет скелет алгоритма. Этот класс содержит методы, некоторые из которых являются абстрактными и должны быть реализованы в подклассах. Конкретные подклассы переопределяют эти абстрактные методы, предоставляя конкретную реализацию шагов алгоритма, сохраняя общую структуру, определенную в базовом классе.


    class AbstractClass:
        def template_method(self):
            self.hook1()
            self.required_operation1()
            self.hook2()
            self.required_operation2()

        def required_operation1(self):
            raise NotImplementedError

        def required_operation2(self):
            raise NotImplementedError

        def hook1(self):
            pass  # Optional hook

        def hook2(self):
            pass  # Optional hook

    class ConcreteClassA(AbstractClass):
        def required_operation1(self):
            print("ConcreteClassA: Implemented Operation1")

        def required_operation2(self):
            print("ConcreteClassA: Implemented Operation2")

    class ConcreteClassB(AbstractClass):
        def required_operation1(self):
            print("ConcreteClassB: Implemented Operation1")

        def required_operation2(self):
            print("ConcreteClassB: Implemented Operation2")

        def hook1(self):
            print("ConcreteClassB: Overridden Hook1")

    # Usage
    a = ConcreteClassA()
    a.template_method()

    b = ConcreteClassB()
    b.template_method()
  

В примере выше, AbstractClass определяет template_method, который определяет порядок выполнения шагов. required_operation1 и required_operation2 являются абстрактными и должны быть реализованы в подклассах. hook1 и hook2 являются "хуками", которые могут быть переопределены подклассами для добавления дополнительного поведения.


Паттерн "Шаблонный метод" (Template Method) - это поведенческий паттерн проектирования, который определяет скелет алгоритма в базовом классе, но позволяет подклассам переопределять некоторые шаги алгоритма, не изменяя его структуру в целом. Он использует наследование для достижения этой цели.

Вот пример реализации на Python:


  class AbstractClass:
    """
    Определяет скелет алгоритма.
    """
    def template_method(self):
      """
      Определяет порядок вызова примитивных операций для
      реализации алгоритма.  Может вызывать как конкретные, так и
      абстрактные операции.
      """
      self.hook_before() # Hook - опциональный шаг
      self.primitive_operation1()
      self.primitive_operation2()
      self.hook_after()  # Hook - опциональный шаг

    def primitive_operation1(self):
      """
      Требует, чтобы подклассы реализовали эти операции.
      """
      raise NotImplementedError("Подклассы должны реализовать primitive_operation1")

    def primitive_operation2(self):
      """
      Требует, чтобы подклассы реализовали эти операции.
      """
      raise NotImplementedError("Подклассы должны реализовать primitive_operation2")

    def hook_before(self):
      """
      Hook, предоставляющий подклассам возможность переопределить его.
      Он делает это по желанию.
      """
      pass

    def hook_after(self):
      """
      Hook, предоставляющий подклассам возможность переопределить его.
      Он делает это по желанию.
      """
      pass


  class ConcreteClass1(AbstractClass):
    """
    Реализует примитивные операции для выполнения конкретных шагов алгоритма.
    """
    def primitive_operation1(self):
      print("ConcreteClass1: Реализация operation1")

    def primitive_operation2(self):
      print("ConcreteClass1: Реализация operation2")

    def hook_before(self):
      print("ConcreteClass1: Hook before")

  class ConcreteClass2(AbstractClass):
    """
    Реализует примитивные операции другим способом.
    """
    def primitive_operation1(self):
      print("ConcreteClass2: Реализация operation1")

    def primitive_operation2(self):
      print("ConcreteClass2: Реализация operation2")

    def hook_after(self):
      print("ConcreteClass2: Hook after")


  # Пример использования
  concrete_class1 = ConcreteClass1()
  print("ConcreteClass1:")
  concrete_class1.template_method()

  print("\nConcreteClass2:")
  concrete_class2 = ConcreteClass2()
  concrete_class2.template_method()
  

Объяснение:

  • AbstractClass: Это абстрактный класс, который определяет шаблонный метод template_method(). Этот метод задает общую структуру алгоритма. Он вызывает абстрактные методы (primitive_operation1(), primitive_operation2()), которые должны быть реализованы в подклассах, а также может вызывать hook-методы (hook_before(), hook_after()), которые являются необязательными для переопределения.
  • ConcreteClass1 и ConcreteClass2: Это конкретные классы, которые наследуются от AbstractClass и предоставляют конкретные реализации абстрактных методов (primitive_operation1() и primitive_operation2()). Они также могут переопределять hook-методы, чтобы изменить поведение алгоритма.
  • Преимущества: Паттерн "Шаблонный метод" позволяет повторно использовать код, избегать дублирования и обеспечить согласованность в реализации алгоритма. Он также упрощает расширение алгоритма, позволяя добавлять новые шаги или изменять существующие, не затрагивая структуру алгоритма в целом.
  • Использование hook-методов: Hook-методы позволяют подклассам вносить изменения в алгоритм, не переопределяя весь шаблонный метод. Они обеспечивают гибкость и позволяют настроить алгоритм в соответствии с потребностями конкретного класса.
0