Builder
Separate the construction of a complex object from its representation so the same construction process can create different representations.
Intent
Provide a step-by-step construction process for a complex object, allowing the same building procedure to produce different types and representations while keeping the construction code isolated from the object's internal structure.
Problem
You need to create an object that requires many configuration steps, optional parameters, or nested sub-objects. A constructor with dozens of parameters becomes unreadable (the 'telescoping constructor' problem), and not every combination of parameters is valid. You also want to reuse the same construction logic to produce different representations of the object.
Solution
Extract the object construction code into a separate Builder class. Organize the construction into a series of well-named steps (setWhere, addJoin, limit, etc.). Clients call only the steps they need. An optional Director class can encapsulate common construction sequences for reuse.
Participants
- Builder — declares the step-by-step interface for constructing parts of the product
- ConcreteBuilder — implements the builder interface and assembles the product, keeping track of the current state
- Director (optional) — defines the order in which building steps are called to construct common configurations
- Product — the complex object being built, whose internal representation may vary
Advantages
- Constructs objects step by step, deferring or omitting optional steps as needed
- Reuses the same construction code to build different representations of the product
- Isolates complex construction logic from business logic (Single Responsibility Principle)
- Eliminates telescoping constructors and makes object creation code self-documenting
Disadvantages
- Increases overall code complexity by introducing multiple new builder classes
- Requires the client to be aware of the different builder types when no Director is used
- The product is not available until build() is called, so partial objects could be used by mistake if the API is not carefully designed
Real-World Analogy
Building a house follows a fixed general process — lay the foundation, build walls, install the roof, add plumbing and electricity — but the details of each step differ wildly. A wooden cabin and a stone castle go through the same stages, yet the builder (construction crew) makes different choices at every step. You, as the director, specify what you want; the builder figures out how to construct it.
Use Cases
- SQL or NoSQL query builders that assemble queries programmatically
- HTTP request builders with optional headers, body, query parameters, and timeouts
- Complex configuration objects with many optional fields (e.g., server config)
- Document or report generators that produce multiple output formats from the same data
- Test data factories that build domain objects with sensible defaults
Code Examples
Fluent HTTP request builder with method chaining. Each setter returns 'this' for a chainable API, and build() produces an immutable request object.