codejump

AcademyDesign Patterns

Template Method pattern

Fixing the step order of an algorithm in a base class while subclasses fill in the rest, the subclassing it costs to change one step, and a base class open to rewrites.

6 min readUpdated

3 exercises

Waiting at the end of this page.

Template Method makes the opposite trade from Strategy: instead of swapping a whole algorithm from outside, it fixes the algorithm's shape and lets a subclass fill in one or two of its steps from inside.

A Template Method defines the fixed order a multi-step algorithm runs in, and leaves one or two of those steps abstract for a subclass to fill in. It's the opposite trade from Strategy: Strategy swaps the whole algorithm from outside; Template Method fixes the algorithm's shape from inside and lets subclasses vary a specific step.

The problem it solves

You export reports. Every export does the same three things in the same order: fetch the data, format it, save it. The only difference between a CSV export and a JSON export is the formatting step.

If each exporter is written separately, the shared steps are copied:

  • Duplicated code. The fetch and save logic exists in every exporter, and a bug fix has to be repeated.
  • The order can drift. One copy formats before validating, another after.
  • New formats mean a new copy. Adding XML means duplicating the skeleton again.

The fix is to write the skeleton once in a base class, and leave only the varying step for subclasses to provide.

Structure

The base class runs the steps in a fixed order. Subclasses only supply the step that differs
The base class runs the steps in a fixed order. Subclasses only supply the step that differs

Two parts:

  • The abstract class: contains the template method (export()), which calls the steps in order. Common steps are implemented here, varying steps are abstract or have defaults.
  • Concrete classes (CsvExporter, JsonExporter): override only the steps that differ.
class ReportExporter {
  export() {
    const data = this.fetchData();
    const formatted = this.format(data);
    return this.save(formatted);
  }
  fetchData() { return ['a', 'b', 'c']; }
  save(formatted) { return 'saved:' + formatted; }
}

class CsvExporter extends ReportExporter {
  format(data) { return data.join(','); }
}
class JsonExporter extends ReportExporter {
  format(data) { return JSON.stringify(data); }
}

// new CsvExporter().export()  → 'saved:a,b,c'
// new JsonExporter().export() → 'saved:["a","b","c"]'

export() is the template and is never overridden. It always fetches, then formats, then saves. A subclass cannot change the order, only what format does. That is the guarantee: the algorithm's shape stays the same everywhere.

Where it is used in real systems

A test runner owns the order of setup, test and cleanup. You only fill in the steps
A test runner owns the order of setup, test and cleanup. You only fill in the steps
Use caseThe fixed skeletonThe steps you fill in
Test frameworksSetup, run, teardownbeforeEach, the test body, afterEach
Data pipelinesExtract, transform, loadThe transform for each source
Report and file exportersFetch, format, saveThe format
Framework lifecyclesMount, update, unmountYour component's hooks
Request handlingAuthenticate, validate, handle, respondThe handler
Game loopsInput, update, renderEach game's update
Build toolsParse, transform, emitA plugin's transform

Template Methods you already use

  • React class components. The framework calls componentDidMount, render and componentWillUnmount in a fixed order, and you supply the steps.
  • Vue and Angular lifecycle hooks. onMounted, ngOnInit and friends are steps you fill into a lifecycle the framework owns.
  • Jest and Vitest. beforeEach, test and afterEach are slots in a fixed skeleton.
  • Java servlets. HttpServlet.service() calls doGet or doPost depending on the request.
  • NestJS lifecycle hooks such as onModuleInit and onApplicationShutdown.

This is often called the Hollywood principle: don't call us, we'll call you. The framework calls your code at the right moment, and you do not call the framework.

Hooks

Besides mandatory steps, a template can offer hooks: optional steps with a default that does nothing. A subclass overrides one only if it needs to.

TypeScript
abstract class ReportExporter {
  export(): string {
    const data = this.fetchData();
    this.beforeSave(data); // hook, empty by default
    return this.save(this.format(data));
  }
  protected beforeSave(_data: string[]): void {}
  protected abstract format(data: string[]): string;
  protected fetchData(): string[] {
    return ['a', 'b', 'c'];
  }
  protected save(formatted: string): string {
    return 'saved:' + formatted;
  }
}

Template Method or Strategy

Template MethodStrategy
MechanismInheritanceComposition
What variesOne step inside a fixed algorithmThe whole algorithm
When it is chosenAt class definitionAt runtime, can change
CouplingSubclass tied to its parentLoose

Modern advice is to prefer composition, so Strategy is often the first choice. Template Method fits when the skeleton really is fixed and frameworks own the control flow. In JavaScript you can also pass the varying step in as a function, which turns a Template Method into a Strategy.

When not to use it

  • Inheritance is a poor fit. Subclasses are tightly coupled to the base class, and a change to the skeleton can break every one of them.
  • Many variations. With many steps to override, the hierarchy grows and becomes hard to follow.
  • The skeleton is not really fixed. If subclasses keep needing to change the order, the template is wrong.
  • You need runtime switching. A subclass is chosen when the object is created. Use Strategy to swap later.
  • A function argument is enough. In JavaScript, export(format) with a function is simpler than a class hierarchy.

What interviewers ask

  • "What is the Template Method pattern?" A base class defines the skeleton of an algorithm and subclasses fill in specific steps.
  • "Template Method versus Strategy?" Inheritance and a fixed skeleton, versus composition and swappable whole algorithms.
  • "What is the Hollywood principle?" The framework calls your code, and your code does not call the framework.
  • "What are hooks?" Optional steps with a default, overridden only when needed.
  • "Give a real example." Test lifecycle methods, framework component lifecycles, or a data pipeline.

The mistake to avoid

A subclass that overrides the template method itself. If CsvExporter redefines export(), the guarantee that every exporter follows the same order is gone, and the shared skeleton no longer means anything. Keep the template method final where the language allows it, and override only the steps.

The mechanism above, a base class calling methods that subclasses fill in, is the same in JavaScript, Python or Java. Only the syntax changes.

Now practice it

1 challenge · 2 quizzes

Reading this page is the cheap half. These are the exercises that make you use it.