Builder Pattern
The problem
When an object has many optional fields, constructor calls become unreadable. A function with eight parameters forces callers to remember argument order, and most parameters are left as null or a default sentinel. The telescoping constructor antipattern is the common symptom: one constructor for every combination of optional fields, each delegating to a longer one. Adding a ninth parameter breaks every call site.
The Builder pattern moves construction into a dedicated object that collects configuration incrementally. The caller sets only what matters, in any order, and triggers construction in a single terminal step. That step is also the right place to validate that mandatory fields are present and that collected configuration is internally consistent. The product comes back in a fully initialized state or not at all.
Structure
classDiagram class QueryBuilder { -table: string -columns: string -conditions: string[] -limitValue: number|null -orderByColumn: string +select(columns) QueryBuilder +from(table) QueryBuilder +where(condition) QueryBuilder +orderBy(col, dir) QueryBuilder +limit(n) QueryBuilder +build() string }When to use
- An object requires more than three or four constructor arguments, especially when most are optional.
- You need to produce several representations of the same logical structure (e.g. SQL vs. a query DSL object vs. a log string) from the same assembly steps.
- Construction involves validation that only makes sense after all inputs are known (cross-field invariants).
- You want to prevent callers from holding a partially constructed object and accidentally using it.
Implementation
The SQL QueryBuilder accumulates clauses through method chaining: each setter returns this (or self), and build() validates then assembles the final string. Python’s from is a reserved keyword, so the method is named from_. Go has no default parameter values, so optional clauses use explicit fields; the hasLimit boolean distinguishes “not set” from LIMIT 0, and Build() returns an error rather than panicking.
Click Run TS to execute. First run downloads Babel (~400 KB, cached after that).
Click Run Python to execute. First run downloads Python (~10 MB, cached after that).
Click Run Go to execute. Runs via the Go Playground API.
Tradeoffs
| Pro | Con |
|---|---|
| Eliminates telescoping constructors | More types to maintain |
| Makes optional parameters explicit | Overkill for objects with 2-3 fields |
| Prevents half-constructed objects | Fluent interface can obscure invariants |
| Supports multiple representations | Builder itself can grow unwieldy |
Gotchas
- Mutable builder, immutable product:
build()should copy state rather than expose builder fields on the product. Callers who keep a reference to the builder and mutate it after building should not affect the product. - Validate in
build(), not in setters: individual setters rarely have enough context to enforce cross-field invariants. Collect all inputs first, then validate once. - TypeScript
thisreturn type: returningthisinstead of the concrete class name enables subclassing. In Python, theQueryBuilderannotation on return types breaks if you subclass; useSelf(3.11+) or aTypeVarbound to the class. - Go error accumulation: Go has no method chaining ergonomics for collecting errors across calls. Put all validation in
Build()and return a single error from there. - Calling
build()twice: two calls on the same builder should produce two independent products. Either document single-use or copy internal state inbuild()so subsequent mutations don’t affect earlier products.
References
- Design Patterns: Elements of Reusable Object-Oriented Software, GoF, pp. 97-106, the original Builder chapter
- Effective Java, Item 2: Consider a builder when faced with many constructor parameters, Joshua Bloch
- Fluent Interface, Martin Fowler, the naming and framing of method chaining
- Builder Pattern, Refactoring Guru, worked examples in multiple languages
Related topics
- Design Patterns, the full GoF catalog and pattern index
- Factory, a simpler creational pattern for single-step construction
- Strategy, a behavioral pattern that pairs well with builders for algorithm selection