Last Updated: February 24, 2026
The Template Method Design Pattern is a behavioral design pattern that defines the skeleton of an algorithm in a base class, but allows subclasses to override specific steps of the algorithm without changing its overall structure.
It’s particularly useful in situations where:
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.
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:
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.
Here is what the code looks like when each exporter handles the entire workflow on its own:
While this approach works for two exporters, it introduces several design problems that compound as the system grows:
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.
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.
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.
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.
This is exactly what the Template Method pattern provides.
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:
final (Java/C#) or non-virtual (C++) so subclasses cannot alter the order or skip steps.Think of a base cake recipe as the Template Method.
The recipe defines the overall flow, step by step:
The key idea is that the sequence is fixed by the general recipe. Specific cake types (subclasses) only implement what differs, mainly how the batter is prepared, and they can optionally override the frosting step if they want a custom finish.
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.
We use an abstract class rather than an interface because the base class needs to provide a concrete template method with real logic (the step ordering). An interface cannot contain a method that calls other methods in sequence while enforcing that sequence.
This is one of the few patterns where inheritance is the right tool, not composition.
CsvReportExporter, PdfReportExporter)Each concrete class extends the abstract class and provides implementations for the abstract steps. Optionally overrides hook methods to customize optional behavior.
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).
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.
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.
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.
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.
Each concrete class will extend AbstractReportExporter and implement the format-specific steps.
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.
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.
The client creates the appropriate exporter and calls exportReport(). It does not know or care about the internal steps.
By applying the Template Method pattern, we have:
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).
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).
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.