Repetitive Procedures, Changing Details
Consider the task of processing data. The flow of reading data from a file, processing it, and outputting the result is the same, but the reading method differs between CSV and JSON data sources. Due to this difference, duplicating the entire logic to create separate classes is inefficient.
The Template Method pattern defines the skeleton of an algorithm in a superclass and lets subclasses override the varying steps. It manages the overall flow in one place while flexibly responding to changes in detail implementations.
Structure of the Template Method Pattern
There are two components:
- AbstractClass: Contains the template method defining the algorithm’s skeleton and abstract methods that subclasses must implement.
- ConcreteClass: Overrides the abstract methods to provide specific behaviors.
The template method is usually declared final to prevent subclasses from altering the skeleton itself. Since only the abstract methods are subject to change, the scope of extension is clearly restricted.
Implementing a Data Processor
Let’s implement a processor that reads, processes, and outputs a data file as an example.
public abstract class DataProcessor {
// Template method: Defines the overall flow
public final void process() {
String rawData = readData();
String processed = transform(rawData);
output(processed);
}
// Steps subclasses must implement
protected abstract String readData();
protected abstract String transform(String data);
// Common step: Can be overridden if needed (Hook method)
protected void output(String data) {
System.out.println("Result: " + data);
}
}
We create implementations for processing CSV data and JSON data.
class CsvDataProcessor extends DataProcessor {
@Override
protected String readData() {
// Logic to read a CSV file
return "name,age\nmadplay,30";
}
@Override
protected String transform(String data) {
// Parse and process CSV
return data.replace(",", " | ");
}
}
class JsonDataProcessor extends DataProcessor {
@Override
protected String readData() {
// Logic to read a JSON file
return "{\"name\":\"madplay\",\"age\":30}";
}
@Override
protected String transform(String data) {
// Parse and process JSON
return data.replaceAll("[{}\"]", "");
}
}
The caller does not need to know the specific data format.
DataProcessor processor = new CsvDataProcessor();
processor.process();
// Result: name | age
// madplay | 30
processor = new JsonDataProcessor();
processor.process();
// Result: name:madplay,age:30
Because the process() method is final, subclasses cannot change the overall flow. They can only override readData() and transform(), making the modifiable scope clear.
Hook Method
A method with a default implementation that subclasses can optionally override, like the output() method in the example above, is called a hook. Unlike abstract methods, overriding is optional, not mandatory.
public abstract class DataProcessor {
public final void process() {
if (validate()) { // Hook: Default is true
String rawData = readData();
String processed = transform(rawData);
output(processed);
}
}
// Hook method: Provides a default implementation but can be overridden
protected boolean validate() {
return true;
}
// ... Rest omitted
}
Using hook methods allows subclasses to selectively intervene at specific points in the algorithm.
Why JdbcTemplate is a Template
JdbcTemplate
Spring’s JdbcTemplate hides the repetitive JDBC procedures (acquiring connection → creating statement → executing query → mapping results → cleaning up resources) within a skeleton, leaving developers to provide only the query and result mapping logic. Strictly speaking, JdbcTemplate relies on injecting callbacks (like RowMapper) rather than inheritance, making it closer to the Strategy pattern. However, the design intent of fixing the repetitive procedure as a skeleton and receiving only the variable parts from the outside aligns with the Template Method pattern.
List<Article> articles = jdbcTemplate.query(
"SELECT title, author FROM article WHERE category = ?",
(rs, rowNum) -> new Article(
rs.getString("title"),
rs.getString("author")
),
"Algorithm/CS"
);
The template handles the repetitive boilerplate of connection management and exception handling on your behalf.
RestTemplate
RestTemplate is similar. It frames the common procedure of an HTTP request (connection setup → sending request → reading response → conversion) as a skeleton, requiring the caller only to specify the URL and response type. Like JdbcTemplate, it is callback-based and not a pure Template Method pattern, but the design philosophy of hiding repetitive procedures in a skeleton remains identical.
Article article = restTemplate.getForObject(
"https://api.example.com/articles/{id}",
Article.class,
42
);
AbstractController
Spring MVC’s AbstractController places the common request processing flow (request validation → session check → caching) in the superclass, designing only the handleRequestInternal() method for subclass implementation. Although it is rarely used directly now that annotation-based controllers (@Controller) are mainstream, it serves as an example of how extensively the Template Method pattern is utilized in Spring’s internal design.
Template Method vs. Strategy Pattern
The Template Method and Strategy patterns solve similar problems but with different approaches.
| Criteria | Template Method | Strategy Pattern |
|---|---|---|
| Extension Mechanism | Inheritance (Subclasses override steps) | Composition (Injecting strategy objects) |
| Skeleton Modification | Impossible (final template method) | The entire strategy can be replaced |
| Coupling | Coupling between superclass and subclass | Loose coupling via interfaces |
| Ideal Scenarios | Fixed overall flow, only specific steps change | Replacing the entire algorithm at runtime |
If the overall flow is firmly fixed and only some steps change, the Template Method is appropriate. On the other hand, if the algorithm itself must be swapped freely at runtime, the Strategy pattern is more flexible.
Neither is absolutely superior. You can choose the appropriate one depending on the situation, and as seen with Spring’s JdbcTemplate, there are cases where the Template Method and Strategy (callback) are used together.
Conclusion
The Template Method pattern features a structure where the algorithm’s skeleton is fixed in a superclass, and variable parts are delegated to subclasses. Spring’s JdbcTemplate and RestTemplate are more like variations combined with callbacks than pure Template Method patterns, but the core idea of concealing repetitive procedures within a skeleton and receiving variable parts from the outside remains identical.
In fact, Spring has also shifted from the approach of inheriting AbstractController to using the @Controller annotation. When introducing a template method, it might be better to first consider whether it can be transitioned to a callback or a functional interface before the inheritance hierarchy deepens.