TypeScript Builder Design Pattern

Ibrahim sengun
3 min readDec 31, 2023

--

What is Builder Design Pattern?

The Builder design pattern is a creational design pattern. It works in the construction of complex objects by breaking the construction process into steps. It allows manipulation and alteration of object construction steps. With the Builder design pattern, various types of objects can be produced using the same construction system.

There are a few terminologies in the Builder Design Pattern. These are:

  • Product: The object that will be built.
  • Builder interface: The interface that specifies the necessary requirements for concrete builders.
  • Concrete builder: It handles the requirements specified by the builder interface and builds the product.
  • Director: It manages the builders and organizes the construction steps within the builder.

When should the Builder Design Pattern be used?

This pattern is mostly used in scenarios involving complex object creation that includes various types of specifications. Within each combination of specifications, different types of objects are created. In situations like this, rather than managing all requirements within the constructor — thereby overusing constructor parameters and leading to a long, complex constructor method — it’s suggest to extract and distribute the construction process across distinct classes.

How to implement Builder Design Pattern in TypeScript

Let’s try to apply the Builder design pattern to TypeScript. Imagine we have a pizza restaurant where the chef produces different types of pizzas upon request. However, there are hundreds of types of pizza, so our chef is overwhelmed by work. We try to command the chef by saying, ‘You should prepare all ingredients at once and then produce the pizza.’

So our chef is angry with us — ‘Boss, this isn’t working. I cannot work like this. If you don’t find a solution for this, I will quit.’

When we hear our chef’s complaints, we start to think of a way to reduce the workload of this complex pizza production method. Then, we employ the builder design pattern. We simplify the pizza preparation by separating the construction of the pizza into steps. To produce various types of pizza, we simply change the order of the steps or add new steps.

Builder Design Pattern diagram

Builder design pattern diagram

Builder Design Pattern code

//Final Product
class Pizza {
dough: string = "";
content: string = "";
public showPizza(): void {
console.log(`pizza with ${this.dough} dough and ${this.content}`)
}

}

//Builder Interface
interface IPizza {
reset(): void;
dough(dough: string): void;
content(content: string): void;
}

//Concrete Builder
class MushroomPizza implements IPizza {
private pizza: Pizza;
constructor() {
this.pizza = new Pizza();
}
reset(): void {
this.pizza = new Pizza();
}
dough(dough: string): void {
this.pizza.dough = dough
}
content(content: string): void {
this.pizza.content = content
}

getPizza(): Pizza {
const result = this.pizza;
this.reset();
return result;
}

}

//Concrete Builder
class CheesePizza implements IPizza {
private pizza: Pizza;
constructor() {
this.pizza = new Pizza();
}
reset(): void {
this.pizza = new Pizza();
}
dough(dough: string): void {
this.pizza.dough = dough;
}
content(content: string): void {
this.pizza.content = content;
}
getPizza(): Pizza {
const result = this.pizza;
this.reset();
return result;
}

}

//Director
class Chef {

makeMushroomPizza(pizza: IPizza) {
pizza.reset();
pizza.dough("thin");
pizza.content("mushroom");
}

makeCheesePizza(pizza: IPizza) {
pizza.reset();
pizza.dough("thick");
pizza.content("cheese");
}
}


//Client

const chef = new Chef();
const pizza = new MushroomPizza();
const pizzaType = chef.makeMushroomPizza(pizza);
const finalPizza = pizza.getPizza()

// pizza with thin dough and mushroom
finalPizza.showPizza()

const pizza2 = new CheesePizza();
const pizzaType2 = chef.makeCheesePizza(pizza2);
const finalPizza2 = pizza2.getPizza()

//pizza with thick dough and cheese
finalPizza2.showPizza();

--

--