Free Interactive Course · Design Patterns

Template Method Design Pattern

Fix the shape of an algorithm once and let subclasses fill in the blanks — without letting them rearrange the shape.

Behavioural Patternseasya.k.a. Hollywood Principle
ShareXLinkedIn
In one sentence

Define the skeleton of an algorithm in an operation, deferring some steps to subclasses so they can redefine those steps without changing the algorithm's structure.

01

The problem Template Method solves

The problem

Three nightly import jobs. One pulls a CSV from an SFTP drop, one calls a partner's REST API, one reads a replica database. Everything else about them is identical: acquire a lock so two runs can't overlap, fetch, validate the rows, transform to the internal schema, write in batches, record metrics, release the lock, and on failure alert the on-call channel with the job name.

They were written three months apart by three people, so you have three copies of that sequence. They are not quite the same. The API job releases the lock in a finally; the CSV job doesn't, so a crash leaves it locked until someone notices at 6am. Two of the three record metrics before validation, one after, which is why the dashboards disagree. Only one alerts on failure.

The part that genuinely differs between these jobs is fetch and parse — maybe forty lines out of three hundred. The other two hundred and sixty are the same idea, written three times, wrong in three different ways.

02

How the Template Method pattern works

Write the sequence once, in a base class, and leave named holes where the jobs actually differ:

  1. A base class holds the template method: the full algorithm, in order, calling steps by name. Mark it final so no subclass can reorder it.
  2. Steps that every job must supply are abstract — fetch(), parse(). The compiler makes them mandatory.
  3. Steps most jobs share get a default implementation. Steps some jobs want are hooks: empty methods a subclass may override and usually doesn't.
  4. Subclasses supply the differences and nothing else. The lock, the ordering, the metrics and the failure alert exist once, and every job gets the fixed version.
This is the Hollywood Principle: "don't call us, we'll call you". Your subclass never calls the framework — the framework calls your subclass, at a moment it chooses. That inversion is what separates a library from a framework, and it's why setUp() in a test class, render() in a React component and doGet() in a servlet all feel the same: you are filling in a hole in someone else's algorithm. It also explains the pattern's main frustration — you get control only at the points the base class decided to offer.
ImportJob (abstract)final run() {lock();rows = fetch(); ← abstractdata = parse(rows); ← abstractvalidate(); write(); metrics();} finally { unlock(); }}CsvImportJobfetch: SFTP · parse: CSVApiImportJobfetch: REST · parse: JSONDbImportJobfetch: replica · parse: rowsthe two violet lines are the only ones a subclass writes — the order is not negotiable
Participants. The Abstract Class holds the template method and declares the primitive operations. Each Concrete Class implements only the primitives. Note the final: the subclass supplies steps, never the sequence — which is precisely the guarantee the three hand-written jobs failed to give.
03

See it: same skeleton, different blanks

The scheduler calls job.run() — the fixed sequence, every time. Choose which import runs and watch which subclass fills the two blanks, while the lock, the validation and the failure alert stay exactly where they are.

▶ Try it — run each import

An interactive template method: the scheduler always calls the same fixed run() sequence — lock, fetch, parse, validate, write, metrics, unlock — and CsvImportJob, ApiImportJob or DbImportJob supplies only the fetch and parse steps.

Add the Kafka job and read the counter: zero edits to the base class. That new job cannot forget to release the lock, cannot record metrics in the wrong place, and cannot skip the failure alert — not because its author was careful, but because those decisions are not available to them. That guarantee is what the pattern is actually selling.
04

Template Method code examples

A sealed skeleton, mandatory blanks, and optional hooks — plus what to do in a language with no inheritance.

public abstract class ImportJob {

    /** final: subclasses fill the steps, they never reorder them. */
    public final ImportResult run() {
        lock.acquire(name());
        try {
            RawBatch raw = fetch();          // abstract — every job must supply
            List<Row> rows = parse(raw);     // abstract
            validate(rows);                  // default, overridable
            beforeWrite(rows);               // hook — usually does nothing
            ImportResult result = writeInBatches(rows);
            metrics.record(name(), result);
            return result;
        } catch (Exception e) {
            alerts.page(name(), e);          // one place, so no job can forget
            throw e;
        } finally {
            lock.release(name());            // ditto
        }
    }

    protected abstract String name();
    protected abstract RawBatch fetch();
    protected abstract List<Row> parse(RawBatch raw);

    /** Default step: most jobs are happy with this. */
    protected void validate(List<Row> rows) {
        rows.forEach(Row::requireMandatoryFields);
    }

    /** Hook: deliberately empty. Override only if you need it. */
    protected void beforeWrite(List<Row> rows) { }
}

public final class CsvImportJob extends ImportJob {
    protected String name()                  { return "csv-import"; }
    protected RawBatch fetch()               { return sftp.download(path); }
    protected List<Row> parse(RawBatch raw)  { return CsvParser.parse(raw); }
}

// HttpServlet.service() is the JDK's own template method: it inspects the HTTP
// verb and calls doGet, doPost or doPut — the hooks you actually override.
Read across the tabs: C++ has the strictest version — the non-virtual interface idiom, where the public entry point can't be overridden and the customisation points are private virtuals. Go can't do it by inheritance at all, so it inverts the pattern into a function plus an interface, with optional steps as optional interfaces — and that inversion is worth stealing in every language, because it composes where a base class doesn't. Python's @final and TypeScript's absence of one are the honest caveat: in those languages "the subclass may not reorder the steps" is a convention, not a guarantee.
05

How to implement Template Method

  1. Write out the algorithm you're duplicating and mark which lines actually differ between the copies. If almost everything differs, this is the wrong pattern.
  2. Put the invariant sequence in the template method and seal it — final, non-virtual, or the non-virtual-interface idiom.
  3. Make genuinely required steps abstract, so the compiler forces every subclass to supply them.
  4. Give common steps a sensible default, and add hooks — empty methods — only where a real subclass needs one. Speculative hooks are dead weight.
  5. Keep the steps protected: they're extension points, not public API. A public step invites callers to run half the algorithm.
  6. Name steps for what they achieve, not when they run — fetch(), not step2().
  7. Prefer the composition form (a function taking the steps) when subclasses would otherwise inherit state or behaviour they don't need.
06

When to use Template Method — and when not to

Use it when several implementations share an algorithm's structure and differ only in specific steps; when you want to factor out duplication and be certain each variant follows the same order; or when you're building a framework and need to control the flow while letting users supply the parts. Test runners, request lifecycles, ETL jobs and rendering pipelines are its natural home.

Where it goes wrong

The fragile base class. Every subclass depends on the base class's internals and call order, so an innocuous change to the skeleton can break subclasses you didn't know existed — sometimes in other repositories. This is inheritance's oldest problem and the pattern sits right on top of it.

Hook explosion. Every new requirement adds a beforeX, afterY, shouldZ, until the base class is a soup of empty methods and the flow is impossible to follow. If you have more than a few hooks, you wanted composition.

Deep hierarchies. ImportJob → BatchImportJob → IncrementalBatchImportJob → CsvIncrementalBatchImportJob. Following one execution now means reading four files and knowing which override wins. Keep it to one level.

Subclasses forced to implement steps they don't have. A job with nothing to validate implementing an empty validate() is a sign the template covers two different algorithms.

A template that isn't shared. A base class with one subclass is indirection with no payoff. Wait for the second real implementation.

You want to…UseBecause
Fix an algorithm's steps and vary specific onesTemplate MethodThe order is guaranteed; subclasses fill named blanks.
Swap the whole algorithm at runtimeStrategyStrategy replaces the algorithm by composition; Template Method varies parts of it by inheritance.
Let two hierarchies grow independentlyBridgeBridge composes at runtime; Template Method binds at compile time.
Decide which class to instantiate inside an algorithmFactory MethodFactory Method is very often one step of a template method.
Add behaviour around an operation without touching itDecoratorDecorator wraps from outside; a template method opens holes from inside.
07

Quick check

🧠 Quick check
Why should the template method itself be final (or non-virtual)?

In the wild

JavaHttpServlet.service() inspecting the verb and calling doGet/doPost; AbstractList, where implementing get and size gets you the whole List API.
Pythonunittest.TestCase — run() calls setUp, your test_*, then tearDown, in an order you don't control.
Gosort.Sort — the algorithm is fixed and you supply Len, Less and Swap through sort.Interface.
JavaScriptReact class components: you write render() and componentDidMount(), React decides when they run — the Hollywood Principle in its most-used form.
C#The ASP.NET page lifecycle and ControllerBase filters; Stream, where overriding Read and Write gives you the rest of the API.
C++The non-virtual interface idiom throughout the standard library and Qt — for example QAbstractItemModel, where you implement rowCount and data and the view drives everything else.

Frequently asked questions

What is the difference between Template Method and Strategy?
Both let part of an algorithm vary; the mechanism and the timing differ. Template Method uses inheritance: the base class owns the sequence and a subclass supplies steps, chosen when you pick the class — so the variation is fixed at compile time and a subclass gets only the holes the base class chose to open. Strategy uses composition: the whole algorithm is an object you can swap at runtime, and one object can use several strategies. If you need the order guaranteed, Template Method; if you need the algorithm interchangeable, Strategy.
What is the Hollywood Principle?
"Don't call us, we'll call you" — your code doesn't drive the framework, the framework calls your code at points it decides. Template Method is the pattern that implements it: you supply fetch(), setUp() or render(), and something else chooses when they run. It's also the practical dividing line between a library (you call it) and a framework (it calls you), and it explains the pattern's characteristic frustration — you can only customise at the points the base class offered.
Should the template method be final?
Yes, wherever your language can express it. The sequence is the guarantee you're buying — if a subclass can override the template, it can skip the lock, the metrics or the error handling, and you're back to the duplicated pipelines you set out to fix. Java uses final, C# is non-virtual by default, and C++ has the non-virtual interface idiom where the public method isn't virtual at all and the steps are private virtuals. In Python @final is checked only by type checkers, and TypeScript has no final — there, it's a convention you enforce in review.
What is a hook method?
A step in the template with an empty (or trivially useful) default implementation that subclasses may override but usually don't — beforeWrite(), shouldRetry(). Abstract steps are mandatory; hooks are optional. They're genuinely useful, but they're also how this pattern rots: a base class carrying a dozen empty beforeX/afterY methods has become impossible to follow. Add a hook when a real subclass needs it, never in anticipation.
How do you use Template Method in a language without inheritance, like Go?
Invert it. The skeleton becomes a plain function, and the varying steps become an interface (or a struct of function values) that the function takes as an argument — Run(ctx, src Source). Optional steps become optional interfaces you check with a type assertion, which is Go's equivalent of an overridable hook. You keep the real guarantee, since callers can't reorder steps they never see, and you avoid the fragile base class entirely. It's worth borrowing this shape in languages that do have inheritance, for the same reasons.

Finish the handbook, earn the certificate

All 23 Gang-of-Four patterns, each with a simulator you can click and code in seven languages. Free, no signup.

See all 23 patterns →
Found this course useful? Share it.
ShareXLinkedIn

Comments

0

Join the conversation. Sign in to leave a comment — we'd love to hear your thoughts.