TUTORIAL SERIES

Design Patterns in Python: Template Method

Modular Algorithms

Amir Lavasani
8 min readMar 9, 2024

Have you encountered recurring coding challenges? Imagine having a toolbox of tried-and-true solutions readily available. That’s precisely what design patterns provide. In this series, we’ll explore what these patterns are and how they can elevate your coding skills.

Understanding the Template Method Pattern

What is the Template Method Design Pattern?

The Template Method is a behavioral design pattern that defines the skeleton of an algorithm in the superclass but lets subclasses override specific steps of the algorithm without changing its structure.

Simply put, the Template Method Pattern helps developers create a group of algorithms that share a common structure. It allows for easier management of complexity and encourages a systematic approach when designing related classes.

When to Use the Template Method Pattern:

Use the Template Method pattern when facing the following scenarios:

  1. Extend Specific Steps: Use when clients need to extend particular steps of an algorithm without altering its structure.
  2. Similar but Not Identical Algorithms: Apply when dealing with multiple classes having almost identical algorithms with slight variations, making modification tedious.
  3. Eliminate Code Duplication: Implement when turning a monolithic algorithm into a series of steps, allowing easy extension by subclasses, while consolidating similar implementations to eliminate code duplication.

Practical Example: Web Scraper Template

We will implement a Web Scraper Template to showcase the capabilities of the template method in a practical example.

By encapsulating common steps like sending requests, parsing HTML, and extracting data, this pattern enables a structured and reusable approach to web scraping.

Dall-E generated image with the following concept: A flowchart depicting the standard process of the template method, with branches for customized steps

Terminology and Key Components

The template method pattern employs a straightforward class structure. We define an abstract template class with a TemplateMethod and concrete classes that can override specific steps.

  1. Abstract Template Class: Declares methods acting as steps in the algorithm and the template method, orchestrating these steps in a specific order. Steps may be either abstract or have default implementations.
  2. Concrete Template Classes: Can override all steps but not the template method itself. These classes provide specific implementations for the declared steps, customizing the algorithm.
Template Method design pattern structure diagram. Image from refactoring.guru

Template Method Implementation in Python

Step 1: Abstract Class (Template)

The abstract class defines the structure of the algorithm through a template method, orchestrating the sequence of steps while declaring them as abstract methods, and allowing concrete classes to provide specific implementations.

from abc import ABC, abstractmethod

# Step 1: Abstract Class (Template)
class AbstractTemplate(ABC):
def template_method(self):
"""The template method orchestrating the steps."""
self.step_one()
self.step_two()
self.step_three()

@abstractmethod
def step_one(self):
"""Abstract method representing the first step."""
pass

@abstractmethod
def step_two(self):
"""Abstract method representing the second step."""
pass

@abstractmethod
def step_three(self):
"""Abstract method representing the third step."""
pass

Step 2: Concrete Classes

Concrete classes extend the abstract class, providing concrete implementations for each abstract method, thereby defining the specific steps of the algorithm.

# Step 2: Concrete Class 1
class ConcreteTemplateA(AbstractTemplate):
def step_one(self):
"""Concrete implementation for the first step in Template A."""
print("Performing initialization for Template A.")

def step_two(self):
"""Concrete implementation for the second step in Template A."""
print("Executing core logic for Template A.")

def step_three(self):
"""Concrete implementation for the third step in Template A."""
print("Finalizing and cleaning up for Template A.")
# Step 3: Concrete Class 2
class ConcreteTemplateB(AbstractTemplate):
def step_one(self):
"""Concrete implementation for the first step in Template B."""
print("Setting up resources for Template B.")

def step_two(self):
"""Concrete implementation for the second step in Template B."""
print("Performing specialized processing for Template B.")

def step_three(self):
"""Concrete implementation for the third step in Template B."""
print("Cleaning up connections and resources for Template B.")

Main Section (Client Code)

In the main section (client code), instances of concrete classes are created, and the template method is invoked on these instances to execute the algorithm, demonstrating the flexibility and customization allowed by the Template Method Pattern.


# Main Section
if __name__ == "__main__":
# Creating instances of concrete classes
template_a = ConcreteTemplateA()
template_b = ConcreteTemplateB()

# Using the template method to perform steps
print("Executing Template A:")
template_a.template_method()

print("\nExecuting Template B:")
template_b.template_method()

GitHub Repo 🎉

Explore all code examples and design pattern implementations on GitHub!

Practical Example: Web Scraper Template

Step 1: Abstract Class (Web Scraper Template)

The abstract class defines a template for web scraping with abstract methods representing common steps like sending HTTP requests, parsing HTML content, and extracting data, allowing concrete classes to provide specific implementations.

from abc import ABC, abstractmethod
import requests
import urllib

from bs4 import BeautifulSoup


# Step 1: Abstract Class (Web Scraper Template)
class WebScraperTemplate(ABC):
@abstractmethod
def send_request(self, url):
"""Abstract method for sending HTTP requests."""
pass

@abstractmethod
def parse_html(self, content):
"""Abstract method for parsing HTML content."""
pass

@abstractmethod
def extract_data(self, soup):
"""Abstract method for extracting data from parsed HTML."""
pass

# Template method orchestrating the steps
def scrape_website(self, url):
"""The template method for web scraping."""
content = self.send_request(url)
soup = self.parse_html(content)
data = self.extract_data(soup)
return data

Step 2: Concrete Classes

This concrete class extends the abstract web scraper template, providing a specific implementation using the requests library for sending HTTP requests and BeautifulSoup for HTML parsing, with a focus on extracting hyperlinks from a webpage.

# Step 2: Concrete Class 1 (RequestsAndBeautifulSoupWebScraper)
class RequestsAndBeautifulSoupWebScraper(WebScraperTemplate):
def send_request(self, url):
"""Concrete implementation for sending HTTP requests using requests library."""
response = requests.get(url)
return response.content

def parse_html(self, content):
"""Concrete implementation for parsing HTML content using BeautifulSoup."""
soup = BeautifulSoup(content, 'html.parser')
return soup

def extract_data(self, soup):
"""Concrete implementation for extracting data from parsed HTML."""
# Example: Extracting all hyperlinks from the webpage
links = [a['href'] for a in soup.find_all('a', href=True)]
return links

This concrete class also extends the web scraper template but uses urllib for sending HTTP requests and a custom parser for HTML content, showcasing an alternative approach to web scraping, and extracting email addresses from a webpage using regular expressions.

# Step 3: Concrete Class 2 (UrllibAndRegexWebScraper)
class UrllibAndRegexWebScraper(WebScraperTemplate):
def send_request(self, url):
"""Concrete implementation for sending HTTP requests using urllib."""
with urllib.request.urlopen(url) as response:
return response.read()

def parse_html(self, content):
"""Concrete implementation for parsing HTML content using custom parser."""
# Custom HTML parsing logic
return content

def extract_data(self, content):
"""Concrete implementation for extracting data using regex."""
import re
# Example: Extracting all email addresses from the webpage
emails = re.findall(r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b', content.decode('utf-8'))
return emails

Client Code

Creates instances of concrete classes, invoking the template method for flexible web scraping with varied underlying algorithms.

# Main Section (Client Code)
if __name__ == "__main__":
# Creating instances of the concrete classes
web_scraper_requests_beautifulsoup = RequestsAndBeautifulSoupWebScraper()
web_scraper_urllib_regex = UrllibAndRegexWebScraper()

# Using the template method to scrape websites
target_url = "https://example.com"

print("Scraped Data using RequestsAndBeautifulSoupWebScraper:")
data_requests_beautifulsoup = web_scraper_requests_beautifulsoup.scrape_website(target_url)
for link in data_requests_beautifulsoup:
print(link)

print("\nScraped Data using UrllibAndRegexWebScraper:")
data_urllib_regex = web_scraper_urllib_regex.scrape_website(target_url)
for email in data_urllib_regex:
print(email)

Real-World Use Cases for Template Method

  1. Django Web Framework (Python): Employs Template Method in view classes for handling HTTP requests, enabling developers to customize specific steps of request processing.
  2. Vue.js Frontend Framework (JavaScript): Implements Template Method in component lifecycle hooks, allowing developers to customize behavior during different phases of a component’s life.
  3. TensorFlow Machine Learning Library (Python): Uses Template Method in model training classes, providing a standardized structure while allowing customization of training steps.
  4. WordPress Theme Development (PHP): Utilizes Template Method in theme classes, allowing customization of the layout, header, and footer within a consistent theme structure.
  5. Angular Framework (TypeScript): Incorporates Template Method in component lifecycle hooks, providing a standardized structure for initialization, change detection, and destruction.

Template Method Best Practices and Potential Drawbacks

When leveraging the Template Method Design Pattern, it’s vital to weigh its advantages and potential challenges:

Pros

  1. Selective Overrides: Clients can override specific parts of a large algorithm, reducing the impact of changes on other sections.
  2. Code Reusability: Duplicate code can be consolidated into a superclass, promoting a more maintainable codebase.

Cons

  1. Client Limitations: Some clients may find their flexibility constrained by the predefined algorithm structure.
  2. Liskov Substitution Principle: Suppressing a default step implementation in a subclass could violate the Liskov Substitution Principle.
  3. Maintenance Challenges: Template methods become harder to maintain with an increasing number of steps.

Best Practices

  1. Clear Abstractions: Establish clear abstractions for components to maintain a cohesive and understandable interface.
  2. Use of Interfaces: Implement interfaces to ensure uniformity among components interacting with the template.
Dall-E generated image with the following concept: AI ego gains consciousness and comprehends the concept of “I”

Template Method’s Relations with Other Patterns

When considering the Template Method pattern, it’s crucial to recognize its connections with other design patterns, each addressing distinct aspects of software architecture.

Template vs. Factory Method Pattern

The Factory Method is a specialized form of the Template Method, and it can also serve as a step within a larger Template Method.

While both involve object creation, the Template Method focuses on algorithmic structure, while the Factory Method is centered around object instantiation.

Template Method vs. Strategy Pattern

Template Method and Strategy patterns diverge in their approach to modifying object behavior. Template Method, reliant on inheritance, facilitates changes by extending parts of an algorithm in subclasses, operating at the class level.

Conversely, the Strategy pattern, relying on composition, enables runtime behavior alterations at the object level by supplying different strategies.

Conclusion

In concluding our journey through the Template Method Pattern in Python, we’ve delved into a pattern that provides a blueprint for algorithmic structures with customizable steps.

The key components, including the abstract class, concrete subclasses, and the template method itself, showcase a robust design for algorithm definition and refinement. We’ve explored the pros and cons of the Template Method, weighing its benefits in algorithm customization against potential limitations.

Additionally, we implemented a practical Web Scraper Template, demonstrating the pattern’s effectiveness in a real-world scenario.

Happy coding! 👩‍💻

Next on the Series 🚀

Read More 📜

The Series 🧭

Explore the GitHub Repo 🎉

References

  1. Design Patterns: Elements of Reusable Object-Oriented Software (Book)
  2. refactoring.guru Template Method
  3. Head First Design Patterns (Book)
  4. Template Method Design Pattern in Java
  5. Template Method Design Pattern

--

--

Amir Lavasani

I delve into machine learning 🤖 and software architecture 🏰 to enhance my expertise while sharing insights with Medium readers. 📃