AlgoMaster Logo

Template Method Design Pattern

Last Updated: February 24, 2026

Ashish

Ashish Pratap Singh

5 min read

It’s particularly useful in situations where:

  • You have a well-defined sequence of steps to perform a task.
  • Some parts of the process are shared across all implementations.
  • You want to allow subclasses to customize specific steps without rewriting the whole algorithm.

Let’s walk through a real-world example and see how we can apply the Template Method Pattern to build flexible, extensible, and reusable workflows.

1. The Problem: Exporting Reports

Let’s say you’re building an analytics platform that lets users export reports in different formats. Right now, the product needs CSV and PDF support, with Excel coming soon.

Each exporter follows the same high-level workflow:

  1. Prepare Data: Gather and organize the report data.
  2. Open File: Create the output file in the target format.
  3. Write Header: Output column headers or metadata (format-specific).
  4. Write Data Rows: Iterate through the dataset and write each row (format-specific).
  5. Write Footer: Add optional summary or footer information.
  6. Close File: Finalize and close the output file.

The workflow is the same across formats. Only the header writing and data row formatting differ. But if you implement each exporter independently, you end up duplicating the shared logic in every class.

Naive Approach

Here is what the code looks like when each exporter handles the entire workflow on its own:

ReportData

CsvReportExporterNaive

PdfReportExporterNaive

Client Code

What’s Wrong with This Design?

While this approach works for two exporters, it introduces several design problems that compound as the system grows:

Code Duplication

The same steps, preparing data, opening the file, closing the file, are repeated verbatim in every exporter class. Add an Excel exporter and you are copying the same boilerplate for the third time. Every line of duplicated code is a future bug waiting to happen.

Maintenance Overhead

If you need to add logging after each export, or change how files are opened (say, to add error handling or buffering), you have to make the same change in every exporter class. Miss one, and that format silently behaves differently. The more formats you add, the worse this gets.

Inconsistent Behavior

Since each exporter manages its own workflow, there is nothing stopping a developer from accidentally reordering steps, skipping the footer, or adding a step in one exporter but not another. The system drifts toward inconsistency over time.

Poor Extensibility

Adding a new export format means copying an entire class and modifying a few lines. This violates the DRY (Don't Repeat Yourself) principle and makes it unclear which parts of the code are shared logic and which parts are format-specific customization.

What We Really Need

  • Define the common report export workflow once, in a single base class
  • Allow subclasses to override only the format-specific steps (header writing, data formatting)
  • Enforce a consistent step ordering so no exporter can accidentally skip or reorder steps
  • Make adding a new format as simple as creating one new subclass with two or three method overrides

This is exactly what the Template Method pattern provides.

2. What is the Template Method Pattern

The Template Method pattern defines the skeleton of an algorithm in a method, deferring some steps to subclasses. It allows you to keep the overall structure of the process consistent, while giving subclasses the flexibility to customize specific parts of the algorithm.

Two characteristics define the pattern:

  1. Algorithm skeleton in the base class: The base class contains a method (the template method) that defines the sequence of steps. This method is typically marked final (Java/C#) or non-virtual (C++) so subclasses cannot alter the order or skip steps.
  2. Subclasses override specific steps: The base class declares abstract methods for the steps that vary. Subclasses implement these methods to provide format-specific or context-specific behavior, but they never control when those methods are called.

Class Diagram

AbstractClass (e.g., AbstractReportExporter)

Contains the template method and defines the algorithm's skeleton. Declares abstract methods for the steps that must vary and provides default implementations for steps that can optionally vary.

Concrete Classes (e.g., CsvReportExporterPdfReportExporter)

Each concrete class extends the abstract class and provides implementations for the abstract steps. Optionally overrides hook methods to customize optional behavior.

Template Method

The method in the abstract class that defines the algorithm's skeleton. Mixes abstract method calls (subclass-provided) with concrete method calls (base-class-provided) and hook calls (optionally overridden).

Hooks

Concrete methods in the abstract class with a default implementation (often empty or trivial) that subclasses can optionally override. Provides extension points without forcing subclasses to implement them.

3. How It Works

The Template Method workflow follows a clear sequence:

Step 1: The client creates an instance of a concrete class (e.g., CsvReportExporter).

Step 2: The client calls the template method (e.g., exportReport()) on the concrete instance.

Step 3: The template method, defined in the abstract base class, begins executing. It calls the steps in the fixed order defined by the skeleton.

Step 4: For each abstract step, the call is dispatched to the concrete subclass's implementation (e.g., writeHeader() calls the CSV-specific version).

Step 5: For each hook, the base class's default runs unless the subclass has overridden it.

Step 6: The template method completes. The client gets a consistent result regardless of which concrete class was used.

4. Implementing Template Method

Let us refactor the report export system using the Template Method pattern. The goal is to extract the common workflow into a single base class and let each format-specific exporter override only the steps that differ.

Step 1: Create the Abstract Base Class

The abstract class contains the template method exportReport(), which defines the fixed sequence of steps. It provides default implementations for shared steps and declares abstract methods for format-specific steps. Hook methods (like writeFooter()) have a default that subclasses can optionally override.

Step 2: Implement Concrete Exporters

Each concrete class will extend AbstractReportExporter and implement the format-specific steps.

CSV Exporter

The CSV exporter extends the abstract class and provides CSV-specific implementations for the two abstract methods. It does not override the hook because CSV reports do not need a footer.

The CSV exporter is clean and focused. It only implements the two methods that are specific to CSV formatting. Everything else, the workflow, the data preparation, the file handling, is inherited from the base class.

Pdf Exporter

The PDF exporter also extends the abstract class but provides different formatting. It overrides the writeFooter hook to add page numbers, something CSV does not need.

Notice how the PDF exporter overrides the writeFooter hook to add page numbering. The CSV exporter did not override it, so it gets the empty default. This is the power of hooks: they let subclasses opt into additional behavior without forcing every subclass to deal with it.

Step 3: Client Code

The client creates the appropriate exporter and calls exportReport(). It does not know or care about the internal steps.

Expected Output:

By applying the Template Method pattern, we have:

  • Eliminated code duplication by moving the shared workflow into a single base class
  • Enforced consistency across all exporters by locking the step order in the template method
  • Made the system extensible, adding a new format only requires creating a new subclass
  • Improved maintainability, changes to shared logic happen in one place
  • Provided clear extension points through abstract methods (required) and hooks (optional)

5. Evolving the System: Adding an Excel Exporter

The real test of any design pattern is what happens when requirements change. The PM now wants Excel export support. With the Template Method pattern in place, this means creating one new subclass. No changes to the base class, no changes to the existing CSV or PDF exporters.

That is the entire change. One new class, three method overrides, zero modifications to existing code. The AbstractReportExporter base class is untouched. The CsvReportExporter and PdfReportExporter are untouched. This is the Open/Closed Principle at work: open for extension (new subclasses), closed for modification (existing code does not change).

6. Practical Example: Online Order Processing

Let us work through a second example to reinforce the pattern. This time, we are building an order processing pipeline for an e-commerce platform. Every order goes through the same sequence of steps: validate the order, calculate the total, process the payment, and send a confirmation.

But the details differ based on the order type: standard orders, Prime orders (free shipping, priority processing), and international orders (customs handling, currency conversion).

Implementation

The OrderProcessor base class controls the pipeline: validate, calculate, discount, pay, confirm. Each order type customizes only what it needs. StandardOrderProcessor uses defaults for discount and confirmation. PrimeOrderProcessor overrides the discount hook to apply member savings. InternationalOrderProcessor overrides the confirmation hook to add multi-language support and tracking.

Adding a new order type (wholesale, subscription, gift) means creating one new subclass. Nothing else changes.