🔄 Behavioral

Template Method Pattern

Defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure, enforcing a consistent sequence of operations.

Problem

You have several classes with algorithms that are almost identical but differ in a few steps. When you change the common algorithm, you must update every class. Duplicating shared logic across subclasses violates DRY and increases the risk of bugs when changes are made inconsistently.

Solution

Move the common algorithm structure into a base class method (the template method). Leave the varying steps as abstract methods or hooks that subclasses override. The template method calls these methods in a specific order, ensuring the overall algorithm structure remains intact while allowing customization of individual steps.

Participants

RoleResponsibility
AbstractClassDefines the template method with the algorithm skeleton; declares abstract steps for subclasses
ConcreteClassImplements the abstract steps to carry out subclass-specific behavior

TypeScript Example

TypeScript
abstract class DataExporter {
  // Template method
  export(data: Record<string, unknown>[]): string {
    const filtered = this.filter(data);
    const formatted = this.format(filtered);
    const header = this.header();
    const footer = this.footer();
    return [header, formatted, footer].filter(Boolean).join("\n");
  }

  protected filter(data: Record<string, unknown>[]) {
    return data;
  }

  protected abstract format(data: Record<string, unknown>[]): string;

  protected header(): string { return ""; }
  protected footer(): string { return ""; }
}

class CsvExporter extends DataExporter {
  protected format(data: Record<string, unknown>[]): string {
    if (data.length === 0) return "";
    const keys = Object.keys(data[0]);
    const header = keys.join(",");
    const rows = data.map((r) => keys.map((k) => r[k]).join(","));
    return [header, ...rows].join("\n");
  }
}

class JsonExporter extends DataExporter {
  protected format(data: Record<string, unknown>[]): string {
    return JSON.stringify(data, null, 2);
  }

  protected header() { return "// Generated export"; }
}

const records = [
  { name: "Alice", age: 30 },
  { name: "Bob", age: 25 },
];

console.log(new CsvExporter().export(records));
console.log("---");
console.log(new JsonExporter().export(records));

Real-World Example

Web frameworks use Template Method for request processing—the framework defines the sequence (parse request, authenticate, authorize, handle, render response) and developers override the handle step. React class component lifecycle (componentDidMount, render, componentDidUpdate) is a template method. Build systems define a pipeline (clean, compile, test, package) where each step can be customized. Testing frameworks use beforeAll/beforeEach/test/afterEach as template methods.

When to Use

  • You want to let clients extend only particular steps of an algorithm, not the whole algorithm or its structure
  • You have several classes with nearly identical algorithms and want to reduce code duplication
  • You want to control which parts of an algorithm subclasses can override and which remain fixed

When Not to Use

  • The algorithm has too many steps that subclasses need to override—consider Strategy instead
  • Subclass-specific behavior doesn't fit neatly into the template's step structure
  • You prefer composition over inheritance for flexibility (consider Strategy or decorator-based approaches)

Understanding the Template Method Pattern

The Template Method pattern is one of the most important behavioral design patterns in object-oriented software design. Originally cataloged by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) in their seminal 1994 book "Design Patterns: Elements of Reusable Object-Oriented Software," this pattern continues to be a cornerstone of modern software architecture.

Defines the skeleton of an algorithm in a method, deferring some steps to subclasses. Template Method lets subclasses redefine certain steps of an algorithm without changing the algorithm's structure, enforcing a consistent sequence of operations. The pattern involves the following key participants: AbstractClass, ConcreteClass. Each participant has a well-defined role, and the interactions between them create a flexible, maintainable structure that can evolve with changing requirements.

In TypeScript and modern JavaScript development, the Template Method pattern is particularly valuable because the language's type system and interface support allow you to express the pattern with compile-time safety. TypeScript generics can make Template Method implementations even more flexible and reusable while maintaining strong type checking throughout the pattern's structure.

Knowing when to apply the Template Method pattern is as important as knowing how. Common use cases include: You want to let clients extend only particular steps of an algorithm, not the whole algorithm or its structure; You have several classes with nearly identical algorithms and want to reduce code duplication; You want to control which parts of an algorithm subclasses can override and which remain fixed. However, overusing design patterns can lead to unnecessarily complex code. Always evaluate whether the pattern genuinely solves your problem or if a simpler approach would suffice.

The Template Method pattern is related to several other design patterns: Strategy, Factory Method, Decorator. Understanding these relationships helps you choose the right pattern for your specific situation and combine patterns effectively when building complex systems.

Related Patterns

More Behavioral Patterns

Explore All Design Patterns

Browse our complete reference of 23 design patterns with TypeScript examples, UML participants, and practical guidance.