Builder is a creational design pattern that lets you construct complex objects step by step. The pattern allows you to produce different types and representations of an object using the same construction code.

Here's an example of implementation in TypeScript:

// Product (House)
class House {
  public walls: string;
  public roof: string;
  public windows: number;
  public doors: number;

  constructor() {
    this.walls = '';
    this.roof = '';
    this.windows = 0;
    this.doors = 0;
  }

  public displayInfo() {
    console.log(`
      House Specifications:
      Walls: ${this.walls}
      Roof: ${this.roof}
      Windows: ${this.windows}
      Doors: ${this.doors}
    `);
  }
}

// Abstract Builder
interface HouseBuilder {
  buildWalls(): void;
  buildRoof(): void;
  buildWindows(): void;
  buildDoors(): void;
  getHouse(): House;
}

// Concrete Builder 1: SimpleHouseBuilder
class SimpleHouseBuilder implements HouseBuilder {
  private house: House;

  constructor() {
    this.house = new House();
  }

  buildWalls() {
    this.house.walls = 'Brick';
  }

  buildRoof() {
    this.house.roof = 'Flat';
  }

  buildWindows() {
    this.house.windows = 4;
  }

  buildDoors() {
    this.house.doors = 2;
  }

  getHouse() {
    return this.house;
  }
}

// Concrete Builder 2: FancyHouseBuilder
class FancyHouseBuilder implements HouseBuilder {
  private house: House;

  constructor() {
    this.house = new House();
  }

  buildWalls() {
    this.house.walls = 'Marble';
  }

  buildRoof() {
    this.house.roof = 'Sloped';
  }

  buildWindows() {
    this.house.windows = 10;
  }

  buildDoors() {
    this.house.doors = 4;
  }

  getHouse() {
    return this.house;
  }
}

// Director
class Contractor {
  private houseBuilder: HouseBuilder;

  constructor(houseBuilder: HouseBuilder) {
    this.houseBuilder = houseBuilder;
  }

  constructHouse() {
    this.houseBuilder.buildWalls();
    this.houseBuilder.buildRoof();
    this.houseBuilder.buildWindows();
    this.houseBuilder.buildDoors();
  }

  getHouse() {
    return this.houseBuilder.getHouse();
  }
}

// Client code
const simpleHouseBuilder = new SimpleHouseBuilder();
const contractor1 = new Contractor(simpleHouseBuilder);
contractor1.constructHouse();
const simpleHouse = contractor1.getHouse();
simpleHouse.displayInfo();

const fancyHouseBuilder = new FancyHouseBuilder();
const contractor2 = new Contractor(fancyHouseBuilder);
contractor2.constructHouse();
const fancyHouse = contractor2.getHouse();
fancyHouse.displayInfo();

In this example, we have a House class representing the product. We also have an HouseBuilder interface that defines the methods for building different parts of the house. The SimpleHouseBuilder and FancyHouseBuilder are concrete builders that implement the HouseBuilder interface to build different types of houses. The Contractor class is the director that oversees the construction process using a specific builder and returns the final house. The client code uses the Contractor with different builders to construct and get different types of houses.

When to use Builder Design Pattern?

  1. Complex object creation: When the creation of an object involves multiple steps, configurations, or optional parameters, the Builder pattern helps organize and simplify the process. It allows you to build the object step by step and configure it as needed.
  2. Configurable object creation: When you need to create objects with different configurations, using the Builder pattern allows you to encapsulate the configuration logic within separate builder classes, making it easier to manage and maintain the codebase.
  3. Creation of immutable objects: The Builder pattern is well-suited for creating immutable objects where all the parameters are set at the time of object construction, and the object state cannot be modified after creation.
  4. Reusability: By separating the construction process from the object representation, the Builder pattern promotes reusability of the same construction algorithm to create different object representations.
  5. Dealing with telescoping constructors: When an object has many optional parameters, using telescoping constructors can lead to confusion and maintenance issues. The Builder pattern offers a cleaner and more readable alternative for object creation with optional parameters.
  6. Enhancing readability: The Builder pattern can improve the readability of code by providing descriptive methods for configuring different parts of the object, making the code more self-explanatory.
  7. Supporting different representations: The Builder pattern can be helpful when you need to support different representations of an object, such as JSON, XML, or other formats. Each builder can handle the conversion from the internal object representation to the desired format.

Overall, the Builder design pattern is a valuable tool for managing complex object creation, providing flexibility, and promoting separation of concerns. It is especially useful when dealing with objects that have various configurations or representations, making the code more maintainable and easier to extend in the future.

Real-World Analogy

  • The product being built is the house with specific configurations and features.
  • The Director is the construction manager or architect who interacts with the client and manages the construction process.
  • The Builder is a set of specialized workers responsible for different aspects of house construction, such as the foundation builder, wall builder, roof builder, plumbing builder, electrical builder, etc.
  • The HouseBuilder interface defines the common construction methods that all builders must implement.
  • ConcreteBuilders are the specific builder implementations for different types of houses, each responsible for constructing a particular style of house with its unique features and configurations.
  • The Director (construction manager) works with the client to understand their requirements and preferences for the house.
  • The Client is the homeowner who specifies their desired house features, layout, and design to the Director (construction manager).
  • The final constructed house, assembled using the Builder pattern, reflects the client's choices and configurations.

By using the Builder design pattern in this real-world analogy, the house construction process becomes more organized, modular, and adaptable. The Director (construction manager) and the ConcreteBuilders (specialized workers) collaborate to create the desired house, allowing the client to customize various aspects without the need for complex constructor arguments or hardcoded configurations.

For example, the client may choose a Victorian-style house with specific room layouts, a modern kitchen, and energy-efficient electrical systems. The Director will direct the appropriate builders to construct the foundation, walls, roof, kitchen, and electrical systems according to the client's preferences.

Overall, the Builder design pattern simplifies and streamlines the process of constructing complex objects like houses, making it easier to create customized and tailored solutions for clients with varying preferences and requirements.

❤️ If you like my work, please follow me and subscribe ❤️