Builder Pattern
The Builder pattern constructs complex objects step by step — ideal when many optional fields, validation rules, or immutable products make telescoping constructors unreadable.
Introduction
The Builder pattern constructs complex objects step by step — ideal when many optional fields, validation rules, or immutable products make telescoping constructors unreadable. Think HttpRequest, PizzaOrder, or GameBoard with configurable size and snakes.
Java records plus compact constructors cover simple cases; Builder shines when defaults, validation, and fluent API improve clarity in LLD interviews.
Distinguish Builder from Factory: Builder assembles one product; Factory selects among products.
Understanding the topic
Key concepts
- Separate construction from representation.
- Fluent interface: chained setter-like methods.
- build() validates and returns immutable product.
- Director optional — orchestrates build steps.
- Java records: builder for many optional fields.
- Static inner Builder common in Java LLD.
Step-by-step explanation
- Define immutable product with required fields.
- Create Builder with defaults for optional fields.
- Each builder method returns this for chaining.
- build() checks invariants, constructs product.
- Reject build() if required fields missing.
- Client uses builder at composition root.
Informative example
Snake and Ladder board built with fluent builder:
public final class GameBoard {private final int size;private final Map<Integer, Integer> jumps;private GameBoard(int size, Map<Integer, Integer> jumps) {this.size = size;this.jumps = Map.copyOf(jumps);}public static Builder builder(int size) { return new Builder(size); }public static final class Builder {private final int size;private final Map<Integer, Integer> jumps = new HashMap<>();private Builder(int size) {if (size <= 0) throw new IllegalArgumentException("size");this.size = size;}public Builder snake(int from, int to) {jumps.put(from, to);return this;}public Builder ladder(int from, int to) {jumps.put(from, to);return this;}public GameBoard build() {jumps.forEach((from, to) -> {if (from < 1 || from > size) throw new IllegalStateException("invalid from");});return new GameBoard(size, jumps);}}}
Builder collects snakes/ladders before immutable GameBoard creation — clear interview narrative.
Real-world use
Real-world applications
- Complex DTOs with many optional parameters.
- Test data setup in unit tests.
- Configuration objects (ElevatorConfig, ParkingLotLayout).
Best practices
- Make product immutable after build().
- Validate only in build(), not every setter.
- Required fields via constructor args to Builder.
- Consider static factory when fields are few.
- Name builder methods domain-specific (withSnake not setJump).
Common mistakes
- Builder for two-field objects (overkill).
- Mutable product after build.
- Partially built object escaping before build().
- Duplicating validation in builder and product.
Advanced interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1BeginnerQuestionWhen use Builder pattern?+
Answer
2BeginnerQuestionBuilder vs constructor?+
Answer
3IntermediateQuestionShould build() be idempotent?+
Answer
4IntermediateQuestionJava records with Builder?+
Answer
5AdvancedQuestionBuild immutable ParkingLot with floors and spots.+
Answer
Summary
Builder assembles complex objects stepwise. Fluent API + build() validation. Immutable products after construction. Use when constructors become unmanageable. Distinct from Factory variant selection.