Hura! Mamy wreszcie przyjemność udostępnić wam polską wersję! Zapraszamy do przesyłania wiadomości z waszymi uwagami i informacjami o zauważonych błędach.
Metoda szablonowa

Metoda szablonowa w języku Python

Metoda szablonowa to behawioralny wzorzec projektowy według którego definiuje się szkielet algorytmu w klasie bazowej i pozwala klasom pochodnym nadpisać poszczególne jego etapy bez zmiany ogólnej struktury.

Użycie wzorca w języku Python

Złożoność:

Popularność:

Przykłady użycia: Metoda szablonowa jest dość powszechnie stosowana we frameworkach Python. Twórcy oprogramowania często za jej pomocą dają użytkownikom frameworku możliwość rozszerzenia jego standardowej funkcjonalności poprzez dziedziczenie.

Identyfikacja: Zastosowanie tego wzorca można poznać po obecności behawioralnych metod posiadających jakieś domyślne zachowanie zdefiniowane przez klasę bazową.

Przykład koncepcyjny

Poniższy przykład ilustruje strukturę wzorca Metoda szablonowa ze szczególnym naciskiem na następujące kwestie:

  • Z jakich składa się klas?
  • Jakie role pełnią te klasy?
  • W jaki sposób elementy wzorca są ze sobą powiązane?

main.py: Przykład koncepcyjny

from abc import ABC, abstractmethod


class AbstractClass(ABC):
    """
    The Abstract Class defines a template method that contains a skeleton of
    some algorithm, composed of calls to (usually) abstract primitive
    operations.

    Concrete subclasses should implement these operations, but leave the
    template method itself intact.
    """

    def template_method(self) -> None:
        """
        The template method defines the skeleton of an algorithm.
        """

        self.base_operation1()
        self.required_operations1()
        self.base_operation2()
        self.hook1()
        self.required_operations2()
        self.base_operation3()
        self.hook2()

    # These operations already have implementations.

    def base_operation1(self) -> None:
        print("AbstractClass says: I am doing the bulk of the work")

    def base_operation2(self) -> None:
        print("AbstractClass says: But I let subclasses override some operations")

    def base_operation3(self) -> None:
        print("AbstractClass says: But I am doing the bulk of the work anyway")

    # These operations have to be implemented in subclasses.

    @abstractmethod
    def required_operations1(self) -> None:
        pass

    @abstractmethod
    def required_operations2(self) -> None:
        pass

    # These are "hooks." Subclasses may override them, but it's not mandatory
    # since the hooks already have default (but empty) implementation. Hooks
    # provide additional extension points in some crucial places of the
    # algorithm.

    def hook1(self) -> None:
        pass

    def hook2(self) -> None:
        pass


class ConcreteClass1(AbstractClass):
    """
    Concrete classes have to implement all abstract operations of the base
    class. They can also override some operations with a default implementation.
    """

    def required_operations1(self) -> None:
        print("ConcreteClass1 says: Implemented Operation1")

    def required_operations2(self) -> None:
        print("ConcreteClass1 says: Implemented Operation2")


class ConcreteClass2(AbstractClass):
    """
    Usually, concrete classes override only a fraction of base class'
    operations.
    """

    def required_operations1(self) -> None:
        print("ConcreteClass2 says: Implemented Operation1")

    def required_operations2(self) -> None:
        print("ConcreteClass2 says: Implemented Operation2")

    def hook1(self) -> None:
        print("ConcreteClass2 says: Overridden Hook1")


def client_code(abstract_class: AbstractClass) -> None:
    """
    The client code calls the template method to execute the algorithm. Client
    code does not have to know the concrete class of an object it works with, as
    long as it works with objects through the interface of their base class.
    """

    # ...
    abstract_class.template_method()
    # ...


if __name__ == "__main__":
    print("Same client code can work with different subclasses:")
    client_code(ConcreteClass1())
    print("")

    print("Same client code can work with different subclasses:")
    client_code(ConcreteClass2())

Output.txt: Wynik działania

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass1 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass1 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Same client code can work with different subclasses:
AbstractClass says: I am doing the bulk of the work
ConcreteClass2 says: Implemented Operation1
AbstractClass says: But I let subclasses override some operations
ConcreteClass2 says: Overridden Hook1
ConcreteClass2 says: Implemented Operation2
AbstractClass says: But I am doing the bulk of the work anyway

Metoda szablonowa w innych językach

Wzorce projektowe: Metoda szablonowa w języku Java Wzorce projektowe: Metoda szablonowa w języku C# Wzorce projektowe: Metoda szablonowa w języku C++ Wzorce projektowe: Metoda szablonowa w języku PHP Wzorce projektowe: Metoda szablonowa w języku Ruby Wzorce projektowe: Metoda szablonowa w języku Swift Wzorce projektowe: Metoda szablonowa w języku TypeScript