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

Structure

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

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