Define the skeleton of an algorithm in a base class, deferring some steps to subclasses — letting subclasses redefine steps without changing the algorithm's structure.
The Template Method pattern is a behavioral design pattern that defines the skeleton of an algorithm in a base class, while allowing subclasses to fill in specific steps — without changing the algorithm's overall structure or sequence.
Think of a recipe template: every recipe follows the same steps — prepare ingredients, cook, plate, serve. But each dish implements those steps differently. The template enforces the structure; the specific dish provides the details.
This is a classic example of the Hollywood Principle: "Don't call us, we'll call you." The base class controls the algorithm flow and calls the subclass methods at the right time — the subclass doesn't call the template directly.
Key Idea: Fix the algorithm's structure in one place (base class). Let subclasses customise individual steps without touching the overall flow.
Contains the template method — a final method that defines the algorithm's skeleton. Also contains abstract methods (steps that subclasses must implement) and hooks (optional steps with default implementations).
The method that defines the sequence of steps. Usually marked final so subclasses cannot change the order. It calls abstract methods and hooks in the correct sequence.
Methods declared abstract in the base class. Subclasses must provide their own implementation for each step. These are the variable parts of the algorithm.
Optional steps with a default (often empty) implementation in the base class. Subclasses may override them to inject behaviour at specific points in the algorithm, but they're not required to.
Subclass that implements the abstract steps with its own logic. It can also override hooks to customise optional behaviour. It never changes the template method itself.
Without Template Method, subclasses that share the same algorithm structure each copy the entire flow, leading to:
// Each subclass duplicates the entire algorithm structure
class CSVReport {
void generate() {
parseCSV(); processData(); formatCSV(); save(); // copy
}
}
class PDFReport {
void generate() {
parseJSON(); processData(); formatPDF(); save(); // copy
sendEmail(); // easy to forget or do in wrong order
}
}// Algorithm lives once in the base class — subclasses just fill steps
abstract class ReportGenerator {
final void generateReport() { // fixed skeleton
parseData(); processData(); formatOutput(); save();
if (shouldSendEmail()) sendEmail(); // hook
}
// Subclasses only implement what's different
}Understanding the difference between these two types of steps is key to using Template Method well:
Declared in the base class with no body. Subclasses must provide an implementation. These represent the mandatory variable parts of the algorithm.
// Base class
protected abstract String parseData(String raw);
// Subclass MUST implement this
@Override
protected String parseData(String raw) {
return csvParser.parse(raw);
}Required — every subclass must implement
Declared in the base class with a default (often empty or boolean) body. Subclasses may override them to add optional behaviour at specific points.
// Base class — default: no email
protected boolean shouldSendEmail() {
return false;
}
// Subclass opts in by overriding
@Override
protected boolean shouldSendEmail() {
return true;
}Optional — override only if needed
// Template Method Pattern — Data Report Generator
// ─── Abstract class with the template method ──────────────────
abstract class ReportGenerator {
// TEMPLATE METHOD — defines the fixed algorithm skeleton
// final prevents subclasses from changing the order of steps
public final void generateReport(String data) {
System.out.println("\n=== Generating Report ===");
String parsed = parseData(data);
String processed = processData(parsed);
String formatted = formatOutput(processed);
saveReport(formatted);
if (shouldSendEmail()) { // hook — optional step
sendEmail(formatted);
}
System.out.println("=== Report Done ===\n");
}
// ── Primitive operations — subclasses MUST implement ────
protected abstract String parseData(String raw);
protected abstract String processData(String data);
protected abstract String formatOutput(String data);
// ── Concrete operation — shared by all subclasses ────────
protected void saveReport(String report) {
System.out.println("[Base] Saving report to disk");
}
// ── Hook — subclasses MAY override (optional behaviour) ──
protected boolean shouldSendEmail() { return false; }
protected void sendEmail(String report) {
System.out.println("[Base] Sending report via email");
}
}
// ─── Concrete class 1 ─────────────────────────────────────────
class CSVReportGenerator extends ReportGenerator {
@Override
protected String parseData(String raw) {
System.out.println("[CSV] Parsing CSV data");
return "parsed:" + raw;
}
@Override
protected String processData(String data) {
System.out.println("[CSV] Aggregating rows and computing totals");
return "processed:" + data;
}
@Override
protected String formatOutput(String data) {
System.out.println("[CSV] Formatting as tabular CSV");
return "csv_report:" + data;
}
}
// ─── Concrete class 2 ─────────────────────────────────────────
class PDFReportGenerator extends ReportGenerator {
@Override
protected String parseData(String raw) {
System.out.println("[PDF] Parsing JSON source data");
return "parsed:" + raw;
}
@Override
protected String processData(String data) {
System.out.println("[PDF] Applying filters and grouping");
return "processed:" + data;
}
@Override
protected String formatOutput(String data) {
System.out.println("[PDF] Rendering to PDF layout with charts");
return "pdf_report:" + data;
}
// Override hook to enable email for PDF reports
@Override
protected boolean shouldSendEmail() { return true; }
@Override
protected void sendEmail(String report) {
System.out.println("[PDF] Emailing PDF report to stakeholders");
}
}
// ─── Usage ────────────────────────────────────────────────────
public class Application {
public static void main(String[] args) {
ReportGenerator csv = new CSVReportGenerator();
csv.generateReport("sales_data_q3.csv");
// Parses → Processes → Formats → Saves (no email)
ReportGenerator pdf = new PDFReportGenerator();
pdf.generateReport("sales_data_q3.json");
// Parses → Processes → Formats → Saves → Sends Email
}
}All pipelines share Extract → Transform → Load, but each source/target implements steps differently.
CSVPipeline, DatabasePipeline, APIPipelineAll reports share parse → process → format → save, but CSV, PDF, and HTML differ in each step.
CSVReport, PDFReport, HTMLReportAll game characters follow the same turn structure: decide → act → update state — but enemy types implement decisions differently.
AggressiveBot, DefensiveBot, RandomBotAll handlers share validate → fetch → respond — but each endpoint has its own validation rules and data sources.
UserHandler, ProductHandler, OrderHandlerAll builds share setup → compile → test → deploy — but web, mobile, and backend projects differ in each step.
WebBuild, AndroidBuild, ServerBuild| Aspect | Template Method | Strategy |
|---|---|---|
| Mechanism | Inheritance | Composition |
| Algorithm | Skeleton fixed in base class | Entire algorithm is swappable |
| Granularity | Individual steps vary | Whole strategy varies |
| Runtime swap | No — fixed at class definition | Yes — inject at runtime |
| Prefer when | Steps vary, structure is fixed | Entire behaviour must be swappable |
AbstractList implements most of List by calling abstract methods get() and size(). Subclasses like ArrayList and LinkedList only implement those two methods — the rest of List's algorithm is inherited.
Django's View, ListView, and DetailView use Template Method. The dispatch() method is the template — it calls get(), post(), put() etc. Developers override only the methods they need.
React class components use Template Method. The framework calls render(), componentDidMount(), componentDidUpdate() in a fixed order. You override only the lifecycle methods you care about.
JUnit's test runner calls setUp() → testMethod() → tearDown() in order. Developers implement the test methods; the template ensures proper setup and cleanup around every test.