TypeScript Template Method Design Pattern

Ibrahim sengun
2 min readJan 30, 2024

--

What is template method design pattern?

The template method design pattern is a behavioral design pattern. It provides the ability to split and change the algortihms workings by using super class to outline the algoritihms and lower classes to change and alter the steps of the algorithm.

There are several terminologies in the template method design pattern. These are:

  • Abstract class: it defines the outline of the algorithm.
  • concerete class: It defines the communication structure.
  • Client: This refers to the application or function that communicates with the system.

When should the template method design pattern be used?

The template method design pattern can be used when there is a need to restrict alteration ability of the client. With it, when extending the client can only change the specific steps of the algorithm. This way, the original structure of the algorithm can be protected.

The template method design pattern can also be used to reduce the code duplication that occurs when there are multiple algorithms that have the same base structure but slightly differ in steps.

How to implement template method design pattern in TypeScript

Let’s apply the template method design pattern to TypeScript. First, let’s imagine a scenario where we are computerizing a coffee-making process. Our goal is to create various types of coffee with a minimal amount of work. To achieve this, we disregard the traditional way of multiplying objects by building every different type from scratch. Instead, we decide to break down the base design and split its core elements into steps. Then, by putting these steps in a higher-level abstraction class, we can create our types in a lower class by simply overriding the steps that need to be changed.

Template Method design pattern diagram

Template Method design pattern diagram

Template Method design pattern code

// Abstract class 
abstract class CoffeeTemplate {
makeCoffee(): void {
this.boilWater();
this.brewCoffeeGrounds();
this.pourInCup();
console.log("Coffee is ready!");
}

abstract boilWater(): void;
abstract brewCoffeeGrounds(): void;
abstract pourInCup(): void;
}

// Concrete class
class CoffeeWithHook extends CoffeeTemplate {
boilWater(): void {
console.log("Boiling water");
}

brewCoffeeGrounds(): void {
console.log("Brewing coffee grounds");
}

pourInCup(): void {
console.log("Pouring coffee into cup");
}
}

// Concrete class
class BlackCoffee extends CoffeeTemplate {
boilWater(): void {
console.log("Boiling water");
}

brewCoffeeGrounds(): void {
console.log("Brewing coffee grounds");
}

pourInCup(): void {
console.log("Pouring black coffee into cup");
}
}

// Client code

/*
Boiling water
Brewing coffee grounds
Pouring coffee into cup
Coffee is ready!
*/

const coffeeWithHook = new CoffeeWithHook();
coffeeWithHook.makeCoffee();

/*
Boiling water
Brewing coffee grounds
Pouring black coffee into cup
Coffee is ready!
*/

const blackCoffee = new BlackCoffee();
blackCoffee.makeCoffee();

--

--