Introduction
The Template Method is a behavioral design pattern that defines the skeleton of an algorithm in a method, deferring some steps to subclasses. It allows subclasses to redefine certain steps of an algorithm without changing the algorithm's structure.
Key Concepts
- Algorithm Skeleton: The Template Method defines the structure of an algorithm, leaving the implementation of some steps to subclasses.
- Abstract Methods: Steps that need to be implemented by subclasses are defined as abstract methods.
- Hook Methods: Optional steps that can be overridden by subclasses but have a default implementation.
Advantages
- Code Reuse: Common parts of the algorithm are implemented in the base class, promoting code reuse.
- Flexibility: Subclasses can implement specific steps of the algorithm, providing flexibility.
- Consistency: Ensures that the algorithm's structure remains consistent across different implementations.
Disadvantages
- Inheritance: Relies on inheritance, which can make the design less flexible and harder to understand.
- Complexity: Can introduce complexity if not used carefully, especially with many abstract and hook methods.
Structure
Here's a UML diagram to illustrate the Template Method pattern:
+---------------------+ | AbstractClass | +---------------------+ | +templateMethod() | | +primitiveOperation1() | | +primitiveOperation2() | +---------------------+ ^ | +---------------------+ | ConcreteClass | +---------------------+ | +primitiveOperation1() | | +primitiveOperation2() | +---------------------+
- AbstractClass: Defines the template method and declares abstract methods for the steps that need to be implemented by subclasses.
- ConcreteClass: Implements the abstract methods defined in AbstractClass.
Example
Let's look at a practical example to understand how the Template Method pattern works. We'll create a simple example of a data processing algorithm where the steps to read, process, and save data are defined in a template method.
Abstract Class
from abc import ABC, abstractmethod class DataProcessor(ABC): def process(self): self.read_data() self.process_data() self.save_data() @abstractmethod def read_data(self): pass @abstractmethod def process_data(self): pass @abstractmethod def save_data(self): pass
Concrete Class
class CSVDataProcessor(DataProcessor): def read_data(self): print("Reading data from CSV file") def process_data(self): print("Processing CSV data") def save_data(self): print("Saving processed data to CSV file") class JSONDataProcessor(DataProcessor): def read_data(self): print("Reading data from JSON file") def process_data(self): print("Processing JSON data") def save_data(self): print("Saving processed data to JSON file")
Usage
if __name__ == "__main__": csv_processor = CSVDataProcessor() csv_processor.process() print() json_processor = JSONDataProcessor() json_processor.process()
Output
Reading data from CSV file Processing CSV data Saving processed data to CSV file Reading data from JSON file Processing JSON data Saving processed data to JSON file
Practical Exercise
Exercise
Create a DocumentProcessor
class using the Template Method pattern. The class should have the following steps:
- Open Document: Abstract method to open a document.
- Edit Document: Abstract method to edit the document.
- Save Document: Abstract method to save the document.
Implement two concrete classes: WordDocumentProcessor
and PDFDocumentProcessor
.
Solution
from abc import ABC, abstractmethod class DocumentProcessor(ABC): def process_document(self): self.open_document() self.edit_document() self.save_document() @abstractmethod def open_document(self): pass @abstractmethod def edit_document(self): pass @abstractmethod def save_document(self): pass class WordDocumentProcessor(DocumentProcessor): def open_document(self): print("Opening Word document") def edit_document(self): print("Editing Word document") def save_document(self): print("Saving Word document") class PDFDocumentProcessor(DocumentProcessor): def open_document(self): print("Opening PDF document") def edit_document(self): print("Editing PDF document") def save_document(self): print("Saving PDF document") if __name__ == "__main__": word_processor = WordDocumentProcessor() word_processor.process_document() print() pdf_processor = PDFDocumentProcessor() pdf_processor.process_document()
Output
Opening Word document Editing Word document Saving Word document Opening PDF document Editing PDF document Saving PDF document
Common Mistakes and Tips
- Overusing Inheritance: Be cautious about overusing inheritance. If the algorithm changes frequently, consider using composition instead.
- Complex Hierarchies: Avoid creating complex class hierarchies. Keep the design simple and maintainable.
- Clear Responsibilities: Ensure that each step in the template method has a clear responsibility, making the code easier to understand and maintain.
Conclusion
The Template Method pattern is a powerful tool for defining the skeleton of an algorithm and allowing subclasses to implement specific steps. By understanding and applying this pattern, you can create flexible and reusable code structures that promote consistency and maintainability.
Software Design Patterns Course
Module 1: Introduction to Design Patterns
- What are Design Patterns?
- History and Origin of Design Patterns
- Classification of Design Patterns
- Advantages and Disadvantages of Using Design Patterns
Module 2: Creational Patterns
Module 3: Structural Patterns
Module 4: Behavioral Patterns
- Introduction to Behavioral Patterns
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Module 5: Application of Design Patterns
- How to Select the Right Pattern
- Practical Examples of Pattern Usage
- Design Patterns in Real Projects
- Refactoring Using Design Patterns
Module 6: Advanced Design Patterns
- Design Patterns in Modern Architectures
- Design Patterns in Microservices
- Design Patterns in Distributed Systems
- Design Patterns in Agile Development