Skip to main content

Template Method Pattern

Category: Behavioral
Intent: Define the skeleton of an algorithm in a superclass, letting subclasses override specific steps without changing the algorithm's structure.


Overviewโ€‹

The Template Method pattern defines the overall structure of an algorithm in a base class method while allowing subclasses to customize specific steps. The base class controls the workflow; subclasses fill in the details.

Key characteristics:

  • The superclass defines the algorithm skeleton (the "template method")
  • Individual steps are declared as abstract or overridable methods
  • Subclasses override steps but do not change the overall flow
  • The template method is typically final to prevent subclasses from altering the algorithm structure

โ“ Problem & Solutionโ€‹

The Problem: Imagine you're creating a data mining application that analyzes corporate documents. Users feed the app documents in various formats (PDF, DOC, CSV), and it tries to extract meaningful data from these docs in a uniform format. The first version of the app could work only with DOC files. In the following version, it was able to support CSV files. A month later, you "taught" it to extract data from PDF files. At some point, you noticed that all three classes have a lot of similar code. While the code for dealing with various data formats was entirely different in all classes, the code for data processing and analysis is almost identical. Wouldn't it be great to get rid of the code duplication, leaving the algorithm structure intact? There was another problem related to client code that used these classes. It had lots of conditionals that picked a proper course of action depending on the class of the processing object. If all three processing classes had a common interface or a base class, you'd be able to eliminate the conditionals in client code and use polymorphism when calling methods on a processing object.

The Solution: The Template Method pattern suggests that you break down an algorithm into a series of steps, turn these steps into methods, and put a series of calls to these methods inside a single template method. The steps may either be abstract, or have some default implementation. To use the algorithm, the client is supposed to provide its own subclass, implement all abstract steps, and override some of the optional ones if needed (but not the template method itself).


๐ŸŒ Real-World Analogyโ€‹

The template method approach can be used in mass housing construction. The architectural plan for building a standard house may contain several extension points that would let a potential owner adjust some details of the resulting house. Each building step, such as laying the foundation, framing, building walls, installing plumbing and wiring for electricity, etc., can be slightly changed to make the resulting house a little bit different from others.


๐Ÿ—๏ธ Structureโ€‹


When to Useโ€‹

  • Multiple classes share the same algorithm structure but differ in certain steps
  • You want to control the extension points of an algorithm
  • You want to avoid code duplication by pulling common behavior into a base class
  • You want to enforce an algorithm's invariant steps while allowing customization

How It Worksโ€‹

Data Processing Pipelineโ€‹

public abstract class DataProcessor {

// Template method โ€” defines the skeleton
public final void process(String source) {
String rawData = readData(source);
String parsedData = parseData(rawData);
String processedData = processData(parsedData);

if (shouldSave()) { // hook method
saveData(processedData);
}

log(processedData); // hook method with default behavior
}

// Abstract steps โ€” MUST be implemented by subclasses
protected abstract String readData(String source);
protected abstract String parseData(String rawData);
protected abstract String processData(String parsedData);

// Concrete step โ€” common implementation
protected void saveData(String data) {
System.out.println("๐Ÿ’พ Saving data to default storage");
}

// Hook methods โ€” CAN be overridden, but have defaults
protected boolean shouldSave() {
return true;
}

protected void log(String data) {
System.out.println("๐Ÿ“‹ Processed data length: " + data.length());
}
}

Concrete Implementationsโ€‹

public class CsvDataProcessor extends DataProcessor {

@Override
protected String readData(String source) {
System.out.println("๐Ÿ“„ Reading CSV file: " + source);
return "name,age,city\nAlice,30,NYC\nBob,25,LA";
}

@Override
protected String parseData(String rawData) {
System.out.println("๐Ÿ” Parsing CSV rows");
return rawData.replace(",", " | ");
}

@Override
protected String processData(String parsedData) {
System.out.println("โš™๏ธ Processing CSV data โ€” filtering empty rows");
return Arrays.stream(parsedData.split("\n"))
.filter(line -> !line.isBlank())
.collect(Collectors.joining("\n"));
}
}

public class JsonDataProcessor extends DataProcessor {

@Override
protected String readData(String source) {
System.out.println("๐Ÿ“„ Reading JSON from API: " + source);
return "{\"users\": [{\"name\": \"Alice\"}, {\"name\": \"Bob\"}]}";
}

@Override
protected String parseData(String rawData) {
System.out.println("๐Ÿ” Parsing JSON structure");
return rawData; // already structured
}

@Override
protected String processData(String parsedData) {
System.out.println("โš™๏ธ Processing JSON โ€” extracting user names");
return "Extracted: Alice, Bob";
}

@Override
protected boolean shouldSave() {
return false; // API data is read-only, don't save
}
}

public class XmlDataProcessor extends DataProcessor {

@Override
protected String readData(String source) {
System.out.println("๐Ÿ“„ Reading XML file: " + source);
return "<users><user>Alice</user><user>Bob</user></users>";
}

@Override
protected String parseData(String rawData) {
System.out.println("๐Ÿ” Parsing XML DOM");
return rawData.replaceAll("<[^>]+>", " ").trim();
}

@Override
protected String processData(String parsedData) {
System.out.println("โš™๏ธ Processing XML โ€” normalizing whitespace");
return parsedData.replaceAll("\\s+", ", ");
}

@Override
protected void saveData(String data) {
System.out.println("๐Ÿ’พ Saving to XML-specific database");
}
}

Client Usageโ€‹

DataProcessor csvProcessor = new CsvDataProcessor();
csvProcessor.process("data/users.csv");
// ๐Ÿ“„ Reading CSV file: data/users.csv
// ๐Ÿ” Parsing CSV rows
// โš™๏ธ Processing CSV data โ€” filtering empty rows
// ๐Ÿ’พ Saving data to default storage
// ๐Ÿ“‹ Processed data length: 43

DataProcessor jsonProcessor = new JsonDataProcessor();
jsonProcessor.process("https://api.example.com/users");
// ๐Ÿ“„ Reading JSON from API: https://api.example.com/users
// ๐Ÿ” Parsing JSON structure
// โš™๏ธ Processing JSON โ€” extracting user names
// (no save โ€” shouldSave() returns false)
// ๐Ÿ“‹ Processed data length: 21

Abstract Methods vs. Hook Methodsโ€‹

TypePurposeImplementation
Abstract methodsMandatory steps that subclasses MUST implementprotected abstract void step();
Hook methodsOptional steps with default behaviorprotected void hook() { /* default */ }
Template methodThe algorithm skeleton โ€” calls other methods in orderpublic final void templateMethod()
Concrete methodsFixed steps that don't changeprivate void fixedStep() { ... }

The Hollywood Principle: "Don't call us, we'll call you." The base class calls subclass methods โ€” not the other way around. The framework controls the flow; subclasses just fill in the blanks.


Real-World Examplesโ€‹

Framework/LibraryDescription
java.util.AbstractListget() is abstract; indexOf(), iterator() use it as template steps
java.io.InputStreamread() is abstract; read(byte[], int, int) and skip() are template methods
Spring JdbcTemplateTemplate for database operations โ€” handles connection, exception translation
JUnit lifecycle@BeforeEach โ†’ @Test โ†’ @AfterEach โ€” framework controls the execution order
Servlet HttpServletservice() dispatches to doGet(), doPost(), etc.

Advantages & Disadvantagesโ€‹

AdvantagesDisadvantages
Eliminates code duplicationTight coupling through inheritance
Controls the algorithm structure and extension pointsHard to compose โ€” only one superclass in Java
Enforces the invariant parts of the algorithmCan be confusing if the template has many hooks
Easy to extend with new variantsRisk of "fragile base class" problem

Interview Questionsโ€‹

Q1: What is the Template Method pattern?

The Template Method pattern defines the skeleton of an algorithm in a base class and lets subclasses override specific steps without changing the overall structure. The base class has a template method (often final) that calls a sequence of abstract and hook methods. Subclasses provide implementations for the abstract methods and optionally override hooks.

Q2: What is the Hollywood Principle and how does it relate to Template Method?

"Don't call us, we'll call you." In the Template Method pattern, the base class controls the algorithm flow and calls subclass methods at the right time โ€” subclasses don't call superclass methods to drive the algorithm. This inverts the typical control flow and is the foundation of frameworks (Spring, JUnit) where the framework calls your code.

Q3: What is the difference between abstract methods and hook methods?

Abstract methods are mandatory extension points โ€” subclasses must implement them. Hook methods are optional โ€” they have default implementations that subclasses can override if needed. Hooks let you add optional behavior (like shouldSave() returning a boolean) without forcing every subclass to implement them.

Q4: How does Template Method differ from Strategy?

Template Method uses inheritance โ€” the algorithm structure is in the base class, and subclasses override steps. Strategy uses composition โ€” the entire algorithm is encapsulated in a separate strategy object and injected. Template Method varies parts of an algorithm; Strategy replaces the whole algorithm. Strategy is more flexible (runtime swapping); Template Method is simpler when inheritance fits.

Q5: Can you give a real-world example of Template Method in Java?

java.util.AbstractList โ€” You implement get(int index) and size(), and the class provides indexOf(), contains(), iterator(), etc. as template methods that use your implementations. java.io.InputStream โ€” You implement read(), and read(byte[]), skip(), transferTo() are built on top of it. Spring's JdbcTemplate handles connection management and exception translation while you provide the SQL and result mapping.


Advanced Editorial Pass: Template Method for Invariant Workflow Controlโ€‹

Where It Excelsโ€‹

  • You must enforce algorithm sequence while allowing limited extension points.
  • Compliance or safety constraints require non-overridable orchestration flow.
  • Shared pre/post behavior must remain centralized and auditable.

Risks in Practiceโ€‹

  • Inheritance hierarchies become brittle when variation points are misidentified.
  • Hook methods encourage subclass side effects that violate invariants.
  • Evolution pressure can force repeated base-class changes.

Engineering Checklistโ€‹

  1. Keep template skeleton small, explicit, and non-negotiable.
  2. Define hook contracts clearly (allowed effects, error behavior, timing).
  3. Move high-variance logic to Strategy when inheritance starts to strain.

๐Ÿ”„ Relations with Other Patternsโ€‹

  • Factory Method: Factory Method is a specialization of Template Method. At the same time, a Factory Method may serve as a step in a large Template Method.
  • Strategy: Template Method is based on inheritance: it lets you alter parts of an algorithm by extending those parts in subclasses. Strategy is based on composition: you can alter parts of the object's behavior by supplying it with different strategies that correspond to that behavior. Template Method works at the class level, so it's static. Strategy works on the object level, letting you switch behaviors at runtime.