Home › Low-Level Design › Template Method Pattern
T

Template Method Pattern

Fix the steps, let subclasses fill the blanks. That is the whole pattern in one line.

Low-Level DesignEasy9 min read

Reach for it when three or four jobs march in the same order and differ in only one or two spots. Instead of copying the order into every class, write it down once. In an interview, the moment you spot "same steps, same order, one part varies," this is the pattern that earns points for seeing structure instead of listing classes.

If you remember five things

The whole pattern in one glance. Everything below defends these five.

  1. Intent. A parent owns the algorithm's skeleton (the step order), and subclasses override only the steps that genuinely differ. The order is locked; the variation is isolated.
  2. When to use. Several variants share the same fixed sequence and differ in a few steps, and that order must not change. Shared structure plus small, known variation.
  3. Structure. One abstract base with a final template method that calls abstract steps (must override), concrete steps (default), and hooks (may override). Children supply the slots.
  4. Inverted control. The parent calls down into the child; the child never calls up to orchestrate. "Don't call us, we'll call you." That inversion is what every test runner and servlet container sells.
  5. The classic gotcha. People confuse it with Strategy. Template Method varies steps inside one fixed algorithm via inheritance; Strategy swaps the whole algorithm via composition at runtime.

This is an LLD design pattern. The goal here is simple: give you enough to draw it, code it, and defend it in a top-company loop without hand-waving.

1The problem it solves#

Start with a case where copy-paste quietly rots. A report exporter is the classic one.

  • You support CSV, JSON, and PDF.
  • Every export does the same dance: open a connection, pull the rows, format them, write the file, close the connection.
  • Four of those five steps are identical across all three formats.
  • Only "format the rows" actually changes.

The naive move is three classes, each with the full five-step method copied in.

  • It works on day one.
  • Then someone adds a "log the export" step, and now you edit three files and forget the third.
  • Three weeks later the PDF exporter is missing the log line, your metrics dashboard shows two formats reporting and one silent, and nobody knows why.

The real problem: the order and the shared steps are one decision that belongs in one place.

  • Copy the skeleton into every class and you have scattered that decision across N files.
  • Every change risks drift.
  • Drift across three copies is exactly the bug that survives code review, because each file looks fine on its own.

Template Method's answer:

  • Write the skeleton once, in a parent.
  • Let each child override only the parts that genuinely differ.
  • The order is locked. The variation is isolated.
  • This is the Open Closed Principle in practice: the algorithm is closed for modification, open for extension through new subclasses.
What the interviewer is actually scoring

Not "can you recite the UML." They want to see you name the shared structure out loud and point at the one step that varies. Spotting "same order, one slot differs" before you draw anything is the signal that you design for change, not just for today.

2The idea (mental model)#

Think of a recipe card that says:

  1. Prep the ingredients
  2. Cook
  3. Plate
  4. Clean up

The card is fixed, the "how" of each step is not.

  • "Cook" means something different for pasta than for steak.
  • The steps and their order are the template.
  • The specific "how" of each step is left to whoever is cooking.

In code, the parent owns one method that calls the steps in order. Often named run() or execute().

  • That method is the template method.
  • It is usually final so nobody can change the order.

The steps it calls come in three flavors:

  • Abstract. The child must implement them. These are the parts that always differ.
  • Concrete. The parent provides a default. The child can leave it alone.
  • Hooks. Empty or near-empty methods the child may override to tweak behavior, but usually does not need to.

The key inversion: the parent calls down into the child.

  • The child never calls up to orchestrate.
  • This is the Hollywood Principle: "don't call us, we'll call you."
  • The framework holds the control flow, and that inverted control is exactly what every test runner and servlet container sells you.

3Structure#

One abstract base class holds the template method and declares the step methods. Concrete subclasses implement the steps that vary. Here is the shape for the exporter example.

classDiagram class ReportExporter { +export() void #fetchRows() List #formatRows(rows) String #writeOutput(body) void #shouldCompress() boolean } class CsvExporter { #formatRows(rows) String } class JsonExporter { #formatRows(rows) String } class PdfExporter { #formatRows(rows) String #shouldCompress() boolean } ReportExporter <|-- CsvExporter ReportExporter <|-- JsonExporter ReportExporter <|-- PdfExporter
The base owns the algorithm; each child owns one or two slots. export() is the public, final template method. formatRows() is abstract, so every child supplies its own. fetchRows() and writeOutput() are shared, written once in the parent. shouldCompress() is a hook with a sensible default, and only PdfExporter bothers to override it.

What a reader learns at a glance:

  • The base owns the algorithm, the children own one or two slots.
  • Each child is about 5 lines instead of 25.
  • That readability is a feature, and it is the thing the interviewer scans your whiteboard for.
Pause before you read on: which method should be final, and which should be abstract, and why does it matter?
Reveal the answer
export(), the template method, should be final: it owns the step order, and a subclass that could override it could reorder or drop steps and defeat the pattern. formatRows() should be abstract: it is the part that always differs, so the base refuses to guess and forces each child to supply it. Lock the orchestration, force the variation, default the rest.

4Implementation in Java#

import java.util.List;

abstract class ReportExporter {

    // The template method. final so nobody reorders the steps.
    public final void export() {
        List<String[]> rows = fetchRows();
        String body = formatRows(rows);
        if (shouldCompress()) {
            body = compress(body);
        }
        writeOutput(body);
        log("Exported " + rows.size() + " rows");
    }

    // Shared step, same for everyone.
    protected List<String[]> fetchRows() {
        // pretend this hits the database
        return List.of(
            new String[]{"1", "Ada"},
            new String[]{"2", "Linus"}
        );
    }

    // Shared step.
    protected void writeOutput(String body) {
        System.out.println("Writing:\n" + body);
    }

    // The part that always differs. Children must implement.
    protected abstract String formatRows(List<String[]> rows);

    // Hook: default behavior, override only if you care.
    protected boolean shouldCompress() {
        return false;
    }

    private String compress(String body) {
        return "[gzip]" + body;
    }

    private void log(String message) {
        System.out.println("LOG: " + message);
    }
}

class CsvExporter extends ReportExporter {
    @Override
    protected String formatRows(List<String[]> rows) {
        StringBuilder sb = new StringBuilder();
        for (String[] r : rows) {
            sb.append(String.join(",", r)).append("\n");
        }
        return sb.toString();
    }
}

class JsonExporter extends ReportExporter {
    @Override
    protected String formatRows(List<String[]> rows) {
        StringBuilder sb = new StringBuilder("[");
        for (int i = 0; i < rows.size(); i++) {
            String[] r = rows.get(i);
            sb.append("{\"id\":\"").append(r[0])
              .append("\",\"name\":\"").append(r[1]).append("\"}");
            if (i < rows.size() - 1) sb.append(",");
        }
        return sb.append("]").toString();
    }
}

class PdfExporter extends ReportExporter {
    @Override
    protected String formatRows(List<String[]> rows) {
        return "%PDF rows=" + rows.size();
    }

    @Override
    protected boolean shouldCompress() {
        return true; // PDFs get compressed
    }
}

The caller does not know or care which exporter it holds:

ReportExporter exporter = new JsonExporter();
exporter.export();

Read the payoff in the code:

  • Every exporter runs the same five steps in the same order.
  • The CSV and JSON ones never think about compression.
  • The PDF one flips one hook.
  • Nobody copied the skeleton.
  • A new "log the export" step lands in one place, export(), and all three formats pick it up at once. That is the drift bug from section 1, designed out.

5A real-world example#

You have already used this pattern even if you never named it.

  • JUnit. The test runner calls setUp(), then your @Test method, then tearDown(), in that fixed order. You fill in the slots, you do not control the order. That is Template Method with hooks, and @Before / @After are the hook points.
  • Servlets. HttpServlet has a service() method that inspects the request type and dispatches to doGet(), doPost(), and so on. You override doGet(). The container runs the surrounding flow. You never call service() yourself.
  • Spring's "AbstractXyz" family. Any base named Abstract*Template or that hands you a doInTransaction style callback leans on this idea. JdbcTemplate and RestTemplate are named for it: the lifecycle (open connection, run your query, close, translate exceptions) is fixed, your logic plugs into one slot.
  • Sorting with Comparable. A cousin: the sort algorithm is fixed, you supply compareTo(), the one varying step.

In LLD rounds it hides inside bigger designs:

  • A payment processor that always validates, charges, then notifies, where "charge" differs per gateway (Stripe vs Razorpay vs PayPal).
  • A game turn that always draws, moves, then scores, where "move" differs per piece.
  • A data pipeline with fixed extract/transform/load order and a pluggable transform.

6When to use it, and when not to#

Reach for it when:

  • You have two or more methods that are nearly identical, differing in a few steps.
  • The order of steps must not change across variants. The order is the thing you want to protect.
  • The variation is known and small: a handful of steps, not an open-ended set.

Skip it when:

  • There is really only one varying step and no fixed skeleton around it. Then you want Strategy: pass in the one behavior as an object, no inheritance needed.
  • The variants need to change at runtime. Template Method bakes the choice into the subclass you instantiate. To swap behavior on a live object, Strategy wins because it is composition, not a compile-time extends.
  • You would need deep inheritance trees to express it. Three levels of abstract classes to reuse code is a smell. Composition usually reads better and dodges the fragile base class problem, where a parent edit silently breaks grandchildren.

My whiteboard rule of thumb:

  • Interviewer says "same steps, same order, one or two parts differ": say Template Method.
  • Interviewer says "swap this behavior at runtime" or "the user picks the algorithm": say Strategy.
  • They are close relatives and interviewers love poking at the line. The honest one-liner: Template Method varies steps inside one fixed algorithm via inheritance; Strategy swaps the whole algorithm via composition.
Say the line between the cousins before you are asked

"Template Method varies steps inside one fixed algorithm via inheritance; Strategy swaps the whole algorithm via composition." Deliver that unprompted and you have answered the follow-up they were loading. It shows you chose the pattern on purpose, not by reflex.

7Common mistakes#

Leaving the template method overridable.

  • If export() is not final, a subclass can override it and reorder everything, which defeats the whole point.
  • Lock it with final.

Making every step abstract.

  • Then subclasses must implement all of them and you have gained nothing over three separate unrelated classes.
  • The payoff comes from the shared concrete steps. If nothing is shared, you picked the wrong pattern.

Too many hooks.

  • Five optional override points and the flow becomes impossible to reason about.
  • Each subclass does something subtly different and you cannot tell what export() does without reading every child.
  • Keep hooks few and well named: one or two is plenty.

Steps that leak into each other through shared mutable state.

  • If formatRows() secretly sets a field that writeOutput() reads, the steps are no longer independent.
  • A subclass that overrides one then breaks the other.
  • Pass data through parameters and return values, as above with rows and body.

Confusing it with Strategy and mixing them.

  • Template Method uses inheritance and a fixed skeleton. Strategy uses composition and a swappable object.
  • Pick one per axis of variation.
  • It is fine to use both in one design, but be clear about which does what.

Protected vs private confusion.

  • The varying steps must be protected (or at least package-visible) so subclasses can override them.
  • The pure helpers that never vary should be private, like compress() and log() above.
  • Candidates who make compress() protected for no reason invite accidental overrides and widen the contract they now have to defend.
The misuse that fails you in the room

Reaching for Template Method when the interviewer actually described runtime selection. If the user picks the format from a dropdown at runtime, inheritance bakes the choice in too early and you will fight it. That is Strategy. Picking inheritance when the variation is runtime-swappable is the single most common way candidates misread this pattern.

8Where it shows up in interviews#

A few ways this lands in a real LLD round.

  • Direct ask. "Design an export feature for CSV, JSON, and PDF." The instant you notice the shared steps, name Template Method, draw the base class, mark export() as the final template method, and point at the one abstract step. That signals structure, not just classes.
  • The Strategy follow-up. "What if the user picks the format at runtime from a dropdown?" Lean toward Strategy, or a factory that picks the right subclass. Saying why you would switch (runtime selection favors composition over a baked-in subclass) is the answer they want.
  • The hook question. "What if only PDF needs compression?" That is a hook with a default. Show shouldCompress() returning false in the base and true in one child. It proves you understand "must implement" versus "may override."
  • The anti-pattern probe. "Why not just copy the method into each class?" Answer with drift: one new step means editing N files and missing one. The template centralizes the order so a change happens once. Tie it back to Open Closed and Don't Repeat Yourself.

Keep your example small.

  • Three subclasses, one abstract step, one hook.
  • That is enough to show mastery and leaves room to talk through tradeoffs instead of typing boilerplate for 20 minutes.
Follow-ups the interviewer will ask (and your answers)
"How is this different from Strategy? When would you switch?"
Template Method varies steps inside one fixed algorithm via inheritance; Strategy swaps the whole algorithm via composition. I switch to Strategy when the behavior must change at runtime (the user picks it from a dropdown) or when there is only one varying step and no fixed skeleton worth protecting. Template Method bakes the choice into the subclass you instantiate, so it cannot swap on a live object.
"What if only one variant needs an extra step, like PDF compression?"
A hook. I add a near-empty method with a safe default in the base (shouldCompress() returning false) and override it true in the one child that cares. The template method calls the hook; the other variants inherit the default and never think about it. Hooks are the "may override" slot, distinct from the abstract "must override" steps.
"Why make the template method final? What breaks if it is not?"
The template method owns the step order, which is the one thing the pattern exists to protect. If it is not final, a subclass can override it, reorder the steps, drop the log call, or skip validation, and now the guarantee is gone. final says "extend the slots, not the orchestration."
"Is deep inheritance a risk here? What about the fragile base class problem?"
Yes. If I need three levels of abstract classes to reuse code, that is a smell, and a change in the base can silently break grandchildren that depended on the old behavior. I keep the hierarchy one level deep where I can, pass data through parameters and returns instead of shared fields, and if the tree wants to grow I move to composition (Strategy) instead.
"Can two variants share state between steps? Any danger there?"
Danger. If formatRows() sets a field that writeOutput() secretly reads, the steps stop being independent, and a child that overrides one quietly breaks the other. I thread data through method parameters and return values (rows into formatRows, body into writeOutput) so each step is self-contained and safe to override in isolation.

What you can now explain in the room

  • The intent in one line: fix the step order in a parent, let subclasses fill the slots that differ.
  • When to reach for it (shared fixed order, small known variation) and when to skip it (runtime swap, single step, deep trees).
  • The three step types (abstract must-override, concrete default, optional hook) and why the template method is final.
  • Why the control flow is inverted ("don't call us, we'll call you") and where JUnit, Servlets, and JdbcTemplate use it.
  • The classic gotcha: Template Method versus Strategy, inheritance inside one algorithm versus composition swapping the whole one.
  • The common misuses: too many hooks, everything abstract, leaky shared state, and protected-versus-private sloppiness.

If this clicked, look at the Strategy pattern next (its runtime-swappable sibling), then Factory Method (which is itself a specialized Template Method for object creation).

Get a prep plan built around your Template Method Pattern interview

Tell us the role and your interview date. We will send back a dated, day by day plan. Free.

Thanks. Check your inbox, your Template Method Pattern prep plan is on the way.