Back to All Design Patterns
Pattern 3 of 22
Creational PatternBEGINNER7 min deep dive
Builder Pattern Pattern
Separates the construction of a complex object from its representation, allowing the same construction process to create different representations.
Real-World Mental Model / Metaphor:
Customizing a pizza or building a custom gaming PC. Rather than passing 18 parameters to a giant constructor (`new PC(cpu, gpu, ram, rgb, liquidCooling...)`), you assemble parts step-by-step.
Interactive Runtime Simulator
Test and tweak inputs dynamicallyInteractive Builder Pattern SimulatorLIVE PLAYGROUND
Interact with the controls below to see how this design pattern executes in memory at runtime.
Configure Complex Object Step-by-Step:
Liquid Cooling System:
Wi-Fi 7 Module:
GENERATED FLUENT BUILDER CODEImmutable Result
Computer pc = new Computer.Builder("Intel Core i9 14900K", 32)
.gpu("NVIDIA RTX 4090 (24GB)")
.liquidCooling(true)
.wifi(true)
.build(); // Validates invariants atomically!Constructed Object Inspection:• CPU: Intel Core i9 14900K• Memory: 32GB DDR5• GPU: NVIDIA RTX 4090 (24GB)• Cooling: Custom Liquid Loop• Networking: Wi-Fi 7 + 10GbE LAN
The Problem It Solves
The Telescoping Constructor anti-pattern where a class has 7 constructors with varying optional parameters, making code unreadable and prone to parameter swapping bugs.
The Architectural Solution
Extract object construction code into a separate Builder class with fluent chainable setter methods and a final `build()` validation method.
Pattern Structure & Participants
| Participant | Role & Responsibility | Type |
|---|---|---|
| Product (Immutable) | Complex object with private constructor | class |
| Builder | Contains matching fields and fluent chainable methods | class |
| build() method | Validates constraints and instantiates the product | class |
Collaboration Rules:
- Client chains builder.setA().setB().build()
- Product has no public setters, making it thread-safe and immutable
Production Code Implementation
Builder Pattern.java
// Immutable Product with Static Nested Builder
public final class Computer {
private final String cpu;
private final int ramGb;
private final String gpu;
private final boolean liquidCooling;
private final boolean wifi;
private Computer(Builder builder) {
this.cpu = builder.cpu;
this.ramGb = builder.ramGb;
this.gpu = builder.gpu;
this.liquidCooling = builder.liquidCooling;
this.wifi = builder.wifi;
}
public static class Builder {
// Required parameters
private final String cpu;
private final int ramGb;
// Optional parameters initialized to defaults
private String gpu = "Integrated Graphics";
private boolean liquidCooling = false;
private boolean wifi = true;
public Builder(String cpu, int ramGb) {
this.cpu = cpu;
this.ramGb = ramGb;
}
public Builder gpu(String gpu) {
this.gpu = gpu;
return this;
}
public Builder liquidCooling(boolean liquidCooling) {
this.liquidCooling = liquidCooling;
return this;
}
public Builder wifi(boolean wifi) {
this.wifi = wifi;
return this;
}
public Computer build() {
// Validate business invariant rules
if (liquidCooling && ramGb < 16) {
throw new IllegalStateException("Liquid cooling requires >= 16GB RAM");
}
return new Computer(this);
}
}
} When to Use:
- •To avoid the 'telescoping constructor' with 4+ optional parameters.
- •When creating an immutable domain object that cannot have public setters.
- •When the object creation process must be step-by-step or deferred.
When to Avoid (Anti-Pattern):
- •When objects are simple data transfer objects (DTOs) with 1 or 2 fields.
- •When mutability is explicitly desired and no complex validation invariants exist.
Staff Engineering Interview Insights & Gotchas
- Explain how Builder enforces immutability and thread safety in concurrent environments.
- Demonstrate validation inside `build()`: constructor parameters are verified atomically before object instantiation.