How to implement Builder design pattern using TypeScript?
In this post, I’ll be explain how to implement Builder design pattern using TypeScript. This post is part of the Design Patterns in TypeScript series. If you would like to learn more, please subscribe to my website for new updates.
What is Builder design pattern?
The builder pattern is an object creation software design pattern. Unlike the abstract factory pattern and the factory method pattern whose intention is to enable polymorphism, the intention of the builder pattern is to find a solution to the telescoping constructor anti-pattern.
– Wikipedia
In short, the intent of the Builder design pattern is to separate the construction of a complex object from its representation. By doing so the same construction process can create different representations.
Let us take an example of a car. A car can have so many options like GPS, no. of seats, car type such as compact, city, sports, etc. If we create a type named `Car` then it will be too much responsibility on this type to handle so many options as constructors.
So, to keep the type `Car` in its simple representation, we will create a builder class named `CarBuilder` that can handle setup of such options step by step and return a final car at the end. Notice that I’ve also created an interface named `ICarBuilder` that any car builder class can implement. The definition of each type is shown below:
namespace BuilderPattern {
export class Car
{
wheels: Number;
colour: String;
}
export interface ICarBuilder {
setColour(colour: string): void;
setWheels(count: number): void;
getResult(): Car;
}
export class CarBuilder implements ICarBuilder {
private _car: Car;
constructor() {
this._car = new Car();
}
setColour(colour: string): void {
this._car.colour = colour;
}
setWheels(count: number): void {
this._car.wheels = count;
}
getResult(): Car {
return this._car;
}
}
}
Now, our car builder class is ready to be used. It is fine to directly use car builder class directly and get a car back. However, we can take one more step further to create a car builder director class that assembles a car instance i.e. delegating the construction to a separate builder object as shown below:
/// <reference path="builder.ts" />
namespace BuilderPattern {
export namespace Demo {
export function show() : void {
let car = CarBuilderDirector.construct();
console.log("The colour of car is " + car.colour + " & it has " + car.wheels + " wheels." )
}
export class CarBuilderDirector{
static construct(): Car{
let carBuilder = new CarBuilder();
carBuilder.setColour("Black");
carBuilder.setWheels(4);
return carBuilder.getResult();
}
}
}
}
The output of method named `show` above is:
The colour of car is Black & it has 4 wheels.
The concept is really simple that a client/consumer doesn’t need to know how an object – car in this case is build. It just requests a builder director to construct a car. Internally, this director uses the car builder that knows how to actually build a car. Even if the internal logic is changed how a car is build, the client/consumer will not be affected in above scenario.
I hope this post properly explains how to implement Builder design pattern using TypeScript. Please refer Design Patterns in TypeScript series to learn more about design patterns in TypeScript.
