Posts

Builder

June 15, 2025
Builder Pattern
The Builder Pattern lets you construct complex objects step by step, instead of stuffing all parameters into a bloated constructor or creating dozens of subclasses.
  • When an object has many optional fields or configurations
  • To avoid huge constructors or subclass explosion
  • When you want to build different representations of the same object (e.g., a car and its user manual)

Think of building a house: you don’t pass all the materials to a constructor. Instead, you go step by step:
  1. Build walls
  2. Add doors and windows
  3. Install the roof
Different builders = different styles (wooden cabin, stone castle, etc.)
Ts
// Product: Car
class Car {
  seats?: number;
  engine?: string;
  tripComputer?: boolean;
  gps?: boolean;

  show(): void {
    console.log(this);
  }
}

// Builder Interface
interface Builder {
  reset(): void;
  setSeats(count: number): void;
  setEngine(engine: string): void;
  setTripComputer(hasComputer: boolean): void;
  setGPS(hasGPS: boolean): void;
}

// Concrete Builder: builds a car
class CarBuilder implements Builder {
  private car: Car;

  constructor() {
    this.car = new Car();
  }

  reset(): void {
    this.car = new Car();
  }

  setSeats(count: number): void {
    this.car.seats = count;
  }

  setEngine(engine: string): void {
    this.car.engine = engine;
  }

  setTripComputer(hasComputer: boolean): void {
    this.car.tripComputer = hasComputer;
  }

  setGPS(hasGPS: boolean): void {
    this.car.gps = hasGPS;
  }

  getResult(): Car {
    const result = this.car;
    this.reset(); // ready for next build
    return result;
  }
}

// Director: knows how to build specific car types
class Director {
  constructor(private builder: Builder) {}

  constructSportsCar(): void {
    this.builder.reset();
    this.builder.setSeats(2);
    this.builder.setEngine("Sport Engine");
    this.builder.setTripComputer(true);
    this.builder.setGPS(true);
  }

  constructSUV(): void {
    this.builder.reset();
    this.builder.setSeats(5);
    this.builder.setEngine("SUV Engine");
    this.builder.setTripComputer(true);
    this.builder.setGPS(false);
  }
}

// Client Code
const carBuilder = new CarBuilder();
const director = new Director(carBuilder);

director.constructSportsCar();
const sportsCar = carBuilder.getResult();
sportsCar.show();

director.constructSUV();
const suv = carBuilder.getResult();
suv.show();

Ts
Car { seats: 2, engine: 'Sport Engine', tripComputer: true, gps: true }
Car { seats: 5, engine: 'SUV Engine', tripComputer: true, gps: false }

  • You have a class with lots of optional parameters.
  • You need to build different representations (e.g., objects vs. manuals).
  • You want to reuse construction logic but keep object types separate.

✅ Pros:
  • Build objects step-by-step with optional parts
  • Reuse the same steps to build different products
  • Isolate complex logic into builder classes
  • Enforces the Single Responsibility Principle
❌ Cons:
  • Adds extra classes and interfaces
  • Can be overkill for simple objects
On this page