Developed By
Gautam Kumar - Full stack developer
DEEP DIVE INTO
The Builder Pattern is a creational design pattern that separates the construction of complex objects from their representation. It allows you to create objects step by step, with the ability to customize their content and configuration.
The Builder Pattern is particularly useful when dealing with objects that have many configuration options or when you want to ensure the immutability of the created objects.
Let's dive deep into implementing the Builder Pattern in TypeScript:
Director:
The Director class orchestrates the construction process using a builder.
It knows which steps should be executed in what order.
Builder:
The Builder interface defines a set of methods to build parts of the product.
Concrete builders implement this interface to construct specific products.
Concrete Builder:
A Concrete Builder is a class that implements the Builder interface.
It provides the logic to build a particular product.
Product:
The Product is the complex object that you want to construct.
It may have various attributes and components.
Here's an example of how to implement the Builder Pattern in TypeScript:
javascript// Product
class Car {
constructor(
public make: string,
public model: string,
public year: number,
public engine: string = "V4",
public color: string = "White"
) {}
describe(): string {
return `${this.year} ${this.make} ${this.model} (${this.engine}, ${this.color})`;
}
}
// Builder interface
interface CarBuilder {
setMake(make: string): void;
setModel(model: string): void;
setYear(year: number): void;
setEngine(engine: string): void;
setColor(color: string): void;
build(): Car;
}
// Concrete Builder
class CarBuilderImpl implements CarBuilder {
private car: Car;
constructor() {
this.reset();
}
reset(): void {
this.car = new Car("");
}
setMake(make: string): void {
this.car.make = make;
}
setModel(model: string): void {
this.car.model = model;
}
setYear(year: number): void {
this.car.year = year;
}
setEngine(engine: string): void {
this.car.engine = engine;
}
setColor(color: string): void {
this.car.color = color;
}
build(): Car {
const builtCar = this.car;
this.reset();
return builtCar;
}
}
// Director
class CarDirector {
constructor(private builder: CarBuilder) {}
constructSportsCar() {
this.builder.setMake("Ferrari");
this.builder.setModel("F430");
this.builder.setYear(2023);
this.builder.setEngine("V8");
this.builder.setColor("Red");
}
constructSUV() {
this.builder.setMake("Jeep");
this.builder.setModel("Cherokee");
this.builder.setYear(2023);
this.builder.setEngine("V6");
this.builder.setColor("Black");
}
}
// Usage
const builder = new CarBuilderImpl();
const director = new CarDirector(builder);
director.constructSportsCar();
const sportsCar = builder.build();
console.log("Sports Car:", sportsCar.describe());
director.constructSUV();
const suv = builder.build();
console.log("SUV:", suv.describe());
In this Builder Pattern implementation:
Car
is the product class, which you want to construct.
CarBuilder
is the builder interface that defines the steps required to construct the Car.
CarBuilderImpl
is a concrete builder that implements the CarBuilder
interface.
CarDirector
is the director that orchestrates the construction process using a specific builder.
The client code creates a builder, a director, and uses them to construct different types of cars step by step.
Separates the construction process from the product, allowing you to create complex objects more flexibly.
Ensures that the created object is in a valid state before it is returned.
Supports the construction of various product variants using the same construction code.
The Builder Pattern is particularly helpful when you need to create objects with numerous optional and mandatory parameters. It ensures that the created objects are consistent and valid while offering a clear and flexible construction process.