Builder Pattern

The Builder is a creational design pattern that separates the construction of a complex object from its representation, allowing the same construction process to create different representations. It is ideal when an object has many optional parameters or configuration steps, avoiding telescoping constructors.

Key Principles

  • Step-by-step construction: Build object in phases (e.g., required → optional features).
  • Fluent interface: Chainable methods (.set_x().set_y()) for readability.
  • Director (optional): Orchestrates building process; Builder handles details.
  • Immutability: Final product often immutable.

Structure

  • Product: The complex object being built.
  • Builder: Interface/abstract class with methods for each construction step.
  • Concrete Builder: Implements steps and returns final product.
  • Director (optional): Uses builder to construct specific variants.

Python Example: Computer Builder

from abc import ABC, abstractmethod
from typing import Optional

# Product
class Computer:
    def __init__(self):
        self.cpu: Optional[str] = None
        self.ram: Optional[int] = None
        self.storage: Optional[int] = None
        self.gpu: Optional[str] = None
        self.os: Optional[str] = None

    def __str__(self):
        return f"Computer [CPU={self.cpu}, RAM={self.ram}GB, Storage={self.storage}GB, GPU={self.gpu}, OS={self.os}]"

# Abstract Builder
class ComputerBuilder(ABC):
    @abstractmethod
    def set_cpu(self) -> 'ComputerBuilder':
        pass

    @abstractmethod
    def set_ram(self) -> 'ComputerBuilder':
        pass

    @abstractmethod
    def set_storage(self) -> 'ComputerBuilder':
        pass

    @abstractmethod
    def set_gpu(self) -> 'ComputerBuilder':
        pass

    @abstractmethod
    def set_os(self) -> 'ComputerBuilder':
        pass

    @abstractmethod
    def build(self) -> Computer:
        pass

# Concrete Builder
class GamingComputerBuilder(ComputerBuilder):
    def __init__(self):
        self.computer = Computer()

    def set_cpu(self) -> 'GamingComputerBuilder':
        self.computer.cpu = "Intel i9-13900K"
        return self

    def set_ram(self) -> 'GamingComputerBuilder':
        self.computer.ram = 64
        return self

    def set_storage(self) -> 'GamingComputerBuilder':
        self.computer.storage = 2000  # 2TB SSD
        return self

    def set_gpu(self) -> 'GamingComputerBuilder':
        self.computer.gpu = "NVIDIA RTX 4090"
        return self

    def set_os(self) -> 'GamingComputerBuilder':
        self.computer.os = "Windows 11"
        return self

    def build(self) -> Computer:
        return self.computer

# Optional Director
class ComputerDirector:
    def construct_gaming_pc(self, builder: ComputerBuilder) -> Computer:
        return (builder
                .set_cpu()
                .set_ram()
                .set_storage()
                .set_gpu()
                .set_os()
                .build())

# Usage (Client Code)
if __name__ == "__main__":
    # With Director
    director = ComputerDirector()
    gaming_pc = director.construct_gaming_pc(GamingComputerBuilder())
    print(gaming_pc)

    # Direct fluent usage
    budget_pc = (GamingComputerBuilder()
                 .set_cpu()  # Reuse same builder logic or create new
                 .set_ram()  # Override for budget
                 .set_ram().ram = 16  # Custom tweak
                 .set_storage().storage = 512
                 .set_gpu().gpu = "Integrated"
                 .set_os().os = "Linux"
                 .build())
    print(budget_pc)

Output:

Computer [CPU=Intel i9-13900K, RAM=64GB, Storage=2000GB, GPU=NVIDIA RTX 4090, OS=Windows 11]
Computer [CPU=Intel i9-13900K, RAM=16GB, Storage=512GB, GPU=Integrated, OS=Linux]

When to Use Builder

  • Object has many optional parameters (avoid long constructors).
  • Need different representations from same steps.
  • Want readable, fluent construction (e.g., SQL query builders).

Summary: Builder lets you construct complex objects step-by-step with a fluent interface, keeping construction logic separate from the product.