from abc import ABC, abstractmethod
import logging
# Set up logging
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger("template_method")
[docs]
class AbstractClass(ABC):
"""
Abstract class that defines the skeleton of an algorithm.
Subclasses must implement specific steps of the algorithm.
"""
[docs]
def template_method(self) -> None:
"""
Defines the algorithm's skeleton by calling base operations,
required steps, and hooks in a predefined order.
"""
self.base_operation1()
self.required_operation1()
self.base_operation2()
self.required_operation2()
self.hook()
[docs]
def base_operation1(self) -> None:
"""
A base operation with a default implementation.
"""
logger.info("AbstractClass: Base operation 1")
[docs]
def base_operation2(self) -> None:
"""
A base operation with a default implementation.
"""
logger.info("AbstractClass: Base operation 2")
[docs]
@abstractmethod
def required_operation1(self) -> None:
"""
A required operation that must be implemented by subclasses.
"""
pass
[docs]
@abstractmethod
def required_operation2(self) -> None:
"""
A required operation that must be implemented by subclasses.
"""
pass
[docs]
def hook(self) -> None:
"""
A hook that can be overridden by subclasses but provides a no-op by default.
"""
logger.info("AbstractClass: Default hook implementation")
[docs]
class ConcreteClass1(AbstractClass):
"""
A concrete implementation of the abstract class with its own behavior.
"""
[docs]
def required_operation1(self) -> None:
"""
A required operation that must be implemented by subclasses.
In this case, this method adds its own behavior before or after
calling the base implementation.
"""
logger.info("ConcreteClass1: Required operation 1")
[docs]
def required_operation2(self) -> None:
"""
A required operation that must be implemented by subclasses.
In this case, this method adds its own behavior before or after
calling the base implementation.
"""
logger.info("ConcreteClass1: Required operation 2")
[docs]
def hook(self) -> None:
"""
A hook that can be overridden by subclasses.
This implementation provides a specific behavior.
"""
logger.info("ConcreteClass1: Overridden hook implementation")
[docs]
class ConcreteClass2(AbstractClass):
"""
Another concrete implementation of the abstract class with its own behavior.
"""
[docs]
def required_operation1(self) -> None:
"""
A required operation that must be implemented by subclasses.
In this case, this method calls the base implementation.
"""
logger.info("ConcreteClass2: Required operation 1")
[docs]
def required_operation2(self) -> None:
"""
A required operation that must be implemented by subclasses.
In this case, this method calls the base implementation.
"""
logger.info("ConcreteClass2: Required operation 2")
# No need to override the hook; the default implementation is used.