7.5. Template Method

7.5.1. Rationale

  • EN: Template Method

  • PL: Metoda szablonowa

  • Type: class

7.5.2. Use Cases

  • Bank application with audit trail (all actions)

  • Record task history

  • Audits

7.5.3. Problem

  • Duplicated code

  • Not enforced to record in audit trail

from dataclasses import dataclass


class AuditTrail:
    def record(self) -> None:
        print('Audit')


@dataclass
class TransferMoneyTask:
    __audit_trail: AuditTrail

    def execute(self):
        self.__audit_trail.record()
        print('Transfer Money')


@dataclass
class GenerateReportTask:
    __audit_trail: AuditTrail

    def execute(self):
        self.__audit_trail.record()
        print('Generate Report')


if __name__ == '__main__':
    audit_trail = AuditTrail()
    task = TransferMoneyTask(audit_trail)
    task.execute()
    # Audit
    # Transfer Money

7.5.4. Design

../../_images/designpatterns-templatemethod-gof.png
../../_images/designpatterns-templatemethod-gof-hooks.png

7.5.5. Implementation

../../_images/designpatterns-templatemethod-usecase.png
../../_images/designpatterns-templatemethod-vs-inheritance.png
../../_images/designpatterns-templatemethod-vs-strategy.png
from abc import ABCMeta, abstractmethod
from dataclasses import dataclass


class AuditTrail:
    def record(self) -> None:
        print('Audit')


@dataclass
class Task(metaclass=ABCMeta):
    __audit_trail: AuditTrail = AuditTrail()

    def execute(self) -> None:
        self.__audit_trail.record()
        self._do_execute()
        print('Transfer Money')

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

class GenerateReportTask(Task):
    def _do_execute(self) -> None:
        print('Generate Report')

class TransferMoneyTask(Task):
    def _do_execute(self) -> None:
        print('Transfer Money')


if __name__ == '__main__':
    task = TransferMoneyTask()
    task.execute()
    # Audit
    # Transfer Money

7.5.6. Assignments