0/0
Design Patterns

Builder Pattern

A creational pattern that separates the construction of a complex object from its representation, so the same construction process can produce different objects β€” and no intermediate, half-built object ever escapes into the wild.

Explore Topics

🎁
Intent
Separate construction from representation
🏭 Builder Assembly Cockpit β€” Director (Classical) and Fluent (modern) side by side
Choose Concrete Builder:
Step 0 / 8
πŸ“œ Director.buildRoaster() recipe
Β·builder.buildCoolingTray();
Β·builder.buildExhaustSystem();
Β·builder.buildGasBurner();
Β·builder.buildInnerDrum();
Β·builder.buildMainBody();
Β·builder.buildMotor();
Β·builder.buildPlatform();
Β·builder.buildThermocouples();
πŸ› οΈ Assembling β€” Personal Roaster0 parts
Empty Roaster shell. Click β–Ά Step to drive the Director through one builder.buildXxx() call.
Switch between Personal and Commercial β€” the Director's 8-step recipe is identical, but the Roaster it produces is completely different. Personal even skips one step (no-op) without breaking the recipe.
🎁
Intent
Separate construction from representation

Builder is a **creational** GoF pattern that separates **how** a complex object is constructed from **what** the object ultimately is. A single Director runs the same construction sequence; different Concrete Builders plug into that sequence and produce different Products. Build a House: the Director always calls `foundation β†’ walls β†’ roof β†’ windows β†’ garage`, but the StoneHouseBuilder produces a slate-roofed brick home with a garage, while the WoodHouseBuilder produces a cedar cabin on stilts with no garage at all.

Key Ideas
  • **Construction** (the step sequence) is separated from **representation** (the final Product). The Director owns the sequence, the Builder owns the steps, the Product is the result.
  • The **same** Director recipe drives **different** Concrete Builders to produce **different** Products β€” that is the pattern's defining mechanic.
  • The Product never exists in a half-built state visible to the Client β€” the Builder returns it only after the last step (`getRoaster()` / `build()`).
  • A Concrete Builder can **skip** a step (return immediately) β€” the same Director recipe can produce a Product that lacks one of the parts, without changing the Director.
Strengths
  • ✦One Director, N Concrete Builders, N different Products β€” adding a new Product variant means a new ConcreteBuilder, no change to Director or Client.
  • ✦The complex construction logic is encapsulated in one place (the Concrete Builder) β€” Client code stays a 3-line script: pick a Builder, hand it to the Director, collect the Product.
  • ✦Final Product can be **immutable** β€” all fields can be `final`, set exactly once when the Builder hands them off.
Weaknesses
  • β–³Three new classes for every Product family (Builder interface + N ConcreteBuilders + Director) before you write a single line of business logic.
  • β–³For simple objects (a Point with two coordinates), a constructor is shorter, clearer, and faster.
  • β–³The Director and the Builder both know the Product's shape β€” if the Product grows a new component, BOTH must change in lockstep.
Used in:A **House Construction** demo: a `ConstructionDirector` runs the 5-step recipe (foundation β†’ walls β†’ roof β†’ windows β†’ garage). Two Concrete Builders β€” `StoneHouseBuilder` and `WoodHouseBuilder` β€” plug in different materials at each step. WoodHouseBuilder also implements `buildGarage()` as a no-op because cabins do not have garages. Same recipe, two finished Houses that look nothing alike.
Code Snippets

Quiz

Intent Quiz
QUIZ 1/6
Which statement best captures the **intent** of the Builder pattern?

Diagrams

Builder Pattern β€” GoF structure (5 roles)
Loading diagram...
Runtime flow β€” Client β†’ Director β†’ ConcreteBuilder β†’ Product
Loading diagram...

Practice

Drag each class, interface, or expression into the Builder role it fills. Two items are traps β€” they belong to a DIFFERENT GoF pattern and should be sorted into the trap bucket.
EXERCISE 1/4
interface RoasterBuilder { void buildCoolingTray(); void buildMotor(); ... Roaster getRoaster(); }
public static class Builder { /* static nested, fluent setters, build() */ }
class PersonalRoasterBuilder implements RoasterBuilder { /* small parts, no platform */ }
class CommercialRoasterBuilder implements RoasterBuilder { /* industrial parts, all 8 steps */ }
class Roaster { LinkedList<String> components; void add(String c); }
public final class Computer { private final String hdd, ram; /* immutable */ }
class Director { void buildRoaster(RoasterBuilder b) { b.buildCoolingTray(); ... b.buildThermocouples(); } }
main(): Builder b = new PersonalRoasterBuilder(); director.buildRoaster(b); Roaster r = b.getRoaster();
class LoggerSingleton { private static LoggerSingleton INSTANCE; }
interface ShapeFactory { Shape createShape(String type); }
Builder interface (declares construction steps)
ConcreteBuilder (implements steps for one variant)
Product (the resulting object)
Director (knows the construction algorithm / order)
Client (picks Builder, hands to Director)
NOT part of Builder (belongs to a different pattern)
Order the lines to build a Computer with the Fluent Builder: required HDD + RAM, optional GPU + Bluetooth, then build and use.
EXERCISE 2/4
Drag the lines into the correct order.
.bluetooth(true) // optional via fluent setter
Computer dev = new Computer.Builder("2 TB", "64 GB") // required via Builder constructor
dev.displaySpec("Dev workstation"); // use the immutable Computer
.build(); // finalize β†’ returns the immutable Computer
.graphicsCard(true) // optional via fluent setter
The Director is leaking state across builds β€” find the bug
EXERCISE 3/4
Click on the line you think contains the bug, then press Confirm.
1class Director {
2 private RoasterBuilder currentBuilder; // ← shared state field
3
4 public void buildRoaster(RoasterBuilder builder) {
5 currentBuilder = builder;
6 currentBuilder.buildCoolingTray();
7 currentBuilder.buildExhaustSystem();
8 currentBuilder.buildGasBurner();
9 currentBuilder.buildMotor();
10 // ... 4 more build steps ...
11 }
12}
13
14// Two threads use the SAME Director instance:
15// Thread A: director.buildRoaster(personalBuilder);
16// Thread B: director.buildRoaster(commercialBuilder); // overlaps
17//
18// Result: personal and commercial build calls INTERLEAVE on whichever
19// builder happens to be the current value of currentBuilder.
20// Personal Roaster ends up with Commercial parts and vice versa.
8 common myths about the Builder pattern β€” true or false?
EXERCISE 4/4
Every Builder pattern implementation must have a Director class.
The Builder pattern solves the telescoping-constructor problem.
Builder and Abstract Factory are interchangeable β€” they solve the same problem.
In a Fluent Builder, the setter methods must return `this` to enable chaining.
Calling `build()` twice on the same Builder is always safe and returns the same Product.
A Concrete Builder can implement a step method as a no-op (do nothing).
The Builder pattern is structural, not creational.
The Fluent Builder requires the Product to be immutable.

References

πŸ“š

Gamma, Helm, Johnson, Vlissides β€” Design Patterns: Elements of Reusable Object-Oriented Software (GoF, 1994)

en.wikipedia.org

book
πŸ“š

Joshua Bloch β€” Effective Java, 3rd Edition, Item 2: "Consider a builder when faced with many constructor parameters"

oreilly.com

book
πŸ“„

Refactoring.guru β€” Builder Pattern

refactoring.guru

article
πŸ“š

Freeman, Robson, Bates, Sierra β€” Head First Design Patterns, 2nd Edition (Appendix: Builder)

oreilly.com

book
πŸ“‹

Oracle Java Docs β€” java.lang.StringBuilder (the canonical JDK Builder)

docs.oracle.com

docs
πŸ“‹

Oracle Java Docs β€” java.net.http.HttpRequest.Builder (modern fluent Builder in the JDK)

docs.oracle.com

docs