Template Method
Behavioral Design Patterns
The Problem: The Duplicated Algorithm
Imagine you are building a tool to process different types of data files, like CSV and PDF files. The overall workflow for processing any file is the same:
- Open the file.
- Parse the file's data.
- Process the extracted data.
- Close the file.
Steps 1 and 4 (opening and closing the file) are identical for all file types. However, steps 2 and 3 (parsing and processing) are completely different for a CSV file versus a PDF file.
Without a good pattern, you might end up with duplicated code in each processor class:
public class CsvProcessor {
public void processFile() {
System.out.println("Opening file..."); // Common logic
System.out.println("Parsing CSV data..."); // Specific logic
System.out.println("Processing data from CSV..."); // Specific logic
System.out.println("Closing file..."); // Common logic
}
}
public class PdfProcessor {
public void processFile() {
System.out.println("Opening file..."); // DUPLICATE
System.out.println("Parsing PDF data..."); // Specific logic
System.out.println("Processing data from PDF..."); // Specific logic
System.out.println("Closing file..."); // DUPLICATE
}
}
This violates the DRY (Don't Repeat Yourself) principle. If you need to add logging to the Opening file...
step, you have to remember to change it in both classes, which is error-prone and hard to maintain.
Defining the Skeleton of an Algorithm
The Template Method is a behavioral design pattern that defines the skeleton of an algorithm in a superclass but lets subclasses override specific steps of the algorithm without changing its structure.
The core idea is to create a "template method" in a base class. This method defines the sequence of steps for an algorithm. Some of these steps are implemented directly in the base class (the parts that are common to all subclasses), while other steps are declared as abstract
, forcing subclasses to provide their own implementation for those specific, variant parts.
The Participants
- Abstract Class: This class defines the
templateMethod()
, which contains the skeleton of the algorithm. It also defines the abstract "primitive operations" that subclasses must implement. It can also contain "hooks" which are methods with a default (but overridable) implementation. - Concrete Class: A subclass that implements the abstract primitive operations, providing the specific details for the variant parts of the algorithm.
Example: A Data Processing Framework
Let's refactor our data processing tool using the Template Method pattern.
// The Abstract Class defining the template method
public abstract class DataProcessor {
// This is the Template Method. It is final to prevent subclasses from changing the algorithm's structure.
public final void processFile(String filePath) {
openFile(filePath);
parseData();
processParsedData();
closeFile();
}
// Common steps implemented in the base class
private void openFile(String filePath) {
System.out.println("Opening file: " + filePath);
}
private void closeFile() {
System.out.println("Closing file.");
}
// Abstract "primitive operations" that subclasses MUST implement
protected abstract void parseData();
protected abstract void processParsedData();
}
// A Concrete Class for processing CSV files
public class CsvDataProcessor extends DataProcessor {
@Override
protected void parseData() {
System.out.println("Parsing data from CSV file...");
}
@Override
protected void processParsedData() {
System.out.println("Processing the parsed CSV data...");
}
}
// A Concrete Class for processing PDF files
public class PdfDataProcessor extends DataProcessor {
@Override
protected void parseData() {
System.out.println("Extracting text from PDF file...");
}
@Override
protected void processParsedData() {
System.out.println("Processing the extracted PDF text...");
}
}
// The Client
public class Client {
public static void main(String[] args) {
System.out.println("--- Processing a CSV file ---");
DataProcessor csvProcessor = new CsvDataProcessor();
csvProcessor.processFile("data.csv");
System.out.println("\n--- Processing a PDF file ---");
DataProcessor pdfProcessor = new PdfDataProcessor();
pdfProcessor.processFile("report.pdf");
}
}
Interview Focus: Analysis and Trade-offs
Benefits:
- Code Reuse: It's an excellent way to reuse the common parts of an algorithm, adhering to the DRY principle.
- Enforces Algorithm Structure: By defining the skeleton in the base class (and often making the template method
final
), you can ensure that all subclasses follow the same high-level sequence of steps, preventing them from altering the overall workflow. - Inversion of Control (The "Hollywood Principle"): This is a key concept to mention. The base class calls the methods on the subclass ("Don't call us, we'll call you."). The high-level "framework" code in the abstract class controls the flow, calling the low-level, specific implementations in the concrete class when needed.
Drawbacks:
- Rigid Structure: The pattern is based on inheritance, so the overall structure of the algorithm is fixed at compile time. It's less flexible than the Strategy pattern if you need to change the entire algorithm dynamically at runtime.
- Potential LSP Violation: If a subclass overrides a concrete method or a "hook" in a way that fundamentally changes its expected behavior, it can violate the Liskov Substitution Principle.
How Template Method Relates to Other Concepts
- Template Method vs. Strategy (The Critical Comparison): This is the most important comparison for this pattern.
- Template Method is based on inheritance. It's designed to let subclasses redefine parts of a fixed algorithm.
- Strategy is based on composition. It's designed to let a client swap out the entire algorithm with a different one.
- The Foundation of Frameworks: The Template Method pattern is fundamental to how application frameworks are designed. A framework provides abstract classes with template methods (e.g., a
BaseWebService
with ahandleRequest()
template), and the application developer's job is to create concrete subclasses that "fill in the blanks" with application-specific logic. - Factory Method: The Factory Method is often implemented as one of the steps inside a Template Method. The template defines a high-level algorithm, and one of its primitive operations might be a factory method responsible for creating an object that is needed by subsequent steps in the algorithm.