Back to Design Patterns
Behavioral Pattern

Template Method Pattern

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.

Intermediate10 min read

What is the Template Method Pattern?

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.

Core Participants

Abstract Class

Abstract Class

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).

Template Method

Template Method

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.

Abstract Steps

Primitive Operations (Abstract Steps)

Methods declared abstract in the base class. Subclasses must provide their own implementation for each step. These are the variable parts of the algorithm.

Hooks

Hooks

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.

Concrete Class

Concrete Class

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.

!Problem It Solves

Duplicated Algorithm Structure

Without Template Method, subclasses that share the same algorithm structure each copy the entire flow, leading to:

  • → Duplicated orchestration code across every subclass
  • → Algorithm steps running in different orders in different subclasses
  • → Bug fixes must be applied to every subclass separately
  • → New subclasses must re-implement the full algorithm from scratch

Without Template Method

// 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
    }
}

With Template Method

// 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
}

Abstract Methods vs Hooks

Understanding the difference between these two types of steps is key to using Template Method well:

Abstract Methods

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

Hooks

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

Implementation

// 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
    }
}

When to Use Template Method

ETL / Data Pipelines

All pipelines share Extract → Transform → Load, but each source/target implements steps differently.

CSVPipeline, DatabasePipeline, APIPipeline

Report Generation

All reports share parse → process → format → save, but CSV, PDF, and HTML differ in each step.

CSVReport, PDFReport, HTMLReport

Game AI Turns

All game characters follow the same turn structure: decide → act → update state — but enemy types implement decisions differently.

AggressiveBot, DefensiveBot, RandomBot

Web Request Lifecycle

All handlers share validate → fetch → respond — but each endpoint has its own validation rules and data sources.

UserHandler, ProductHandler, OrderHandler

Build / CI Pipelines

All builds share setup → compile → test → deploy — but web, mobile, and backend projects differ in each step.

WebBuild, AndroidBuild, ServerBuild

Pros & Cons

Advantages

  • Algorithm structure defined once — DRY principle
  • Subclasses only implement what varies — focused and clean
  • Easy to add new variants — just add a new subclass
  • Hooks give fine-grained opt-in control over optional steps
  • Prevents subclasses from accidentally breaking the algorithm order

Disadvantages

  • Requires inheritance — can't use with unrelated classes
  • Liskov Substitution can be violated if hooks are misused
  • Algorithm is harder to follow — logic spread across base + subclasses
  • Adding too many hooks makes the base class complex
  • Strategy pattern is often a more flexible composition-based alternative

Template Method vs Strategy

AspectTemplate MethodStrategy
MechanismInheritanceComposition
AlgorithmSkeleton fixed in base classEntire algorithm is swappable
GranularityIndividual steps varyWhole strategy varies
Runtime swapNo — fixed at class definitionYes — inject at runtime
Prefer whenSteps vary, structure is fixedEntire behaviour must be swappable

Real-World Examples

Java's AbstractList

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 Class-Based Views (Python)

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's Component Lifecycle

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 TestCase (Java)

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.

What's Next?

Now that you understand Template Method, explore related Behavioral patterns: