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:

  1. Open Document: Abstract method to open a document.
  2. Edit Document: Abstract method to edit the document.
  3. 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.

© Copyright 2024. All rights reserved