How does the Builder pattern differ from Factory Method and Abstract Factory, and how would you decide which one a given creation problem calls for?
answer
- factories choose what; builder governs how
- one call vs many stateful calls
- Abstract Factory = family consistency
- builder carries state → optionality + validation
- they compose: factory returns a builder
basics
~20 sFactory Method and Abstract Factory answer "which class do I create?" and do it in one call. Builder answers "how do I assemble this one complicated object?" across many calls. Use a factory to hide the concrete type; use a builder for many optional parts.
solid answer
~60 sAll three are creational, but they vary different axes. **Factory Method** lets subclasses (or an overridable hook) decide which concrete class to instantiate: one call, one product, variation by subclassing. **Abstract Factory** groups several such calls behind one interface so you can swap a whole *family* of related products consistently — `WidgetFactory` producing matching buttons, scrollbars, and menus for a theme. **Builder** varies neither the class nor the family by default; it varies the *assembly* of one product, spread over many stateful calls, which is what lets it handle many optional parts, enforce step order, validate the whole value set at the end, and return an immutable result. The GoF Builder can also vary representation, but via a construction process handed to different concrete builders rather than by selecting a family. Decision heuristic: many optional parameters or a complex step-wise assembly → Builder; hiding a concrete implementation behind one call → Factory Method; keeping several related products consistent with each other → Abstract Factory. They compose: a factory method commonly returns a builder, and a builder's `build()` may delegate to a factory.
go deeper
Give the one-liner: factories decide which object to create in one call; builders assemble one complex object step by step.
Add the axis each pattern varies, note that the builder carries state between calls, and give one concrete example per pattern.
Explain family-consistency as Abstract Factory's real guarantee, show how build() can dispatch to different implementations, and discuss where Prototype and static factory methods fit.
Reason about API surface and evolution: which choice keeps callers stable as parameters and implementations grow, and when none of the three is needed because the language offers named arguments, records, or copy-with functions.
### Definitions, stated plainly - **Factory Method** — a method whose job is to create an object, designed so that *which concrete class* is created can be varied (classically by subclass overriding, in practice often by a switch on a type token or by dependency injection). One call in, one product out. It exists to decouple the caller from the concrete type. Note that a *static factory method* (`Duration.ofSeconds(30)`) is a related but distinct idea — a named alternative to a constructor, not necessarily polymorphic. - **Abstract Factory** — an interface with several creation methods, each producing one member of a *family* of related products, plus concrete factories per family. The guarantee it buys is *mutual consistency*: with `MacWidgetFactory` you cannot accidentally combine a Mac button with a Windows scrollbar, because the caller only ever holds one factory. - **Builder** — a separate object that accumulates the parts of a single complex product over multiple calls and produces it in a terminal `build()`/`getResult()` step. ### The axes each one varies | | Factory Method | Abstract Factory | Builder | |---|---|---|---| | Calls per product | one | one per product | many, then build() | | What varies | the concrete class | the whole product family | the assembly (and, in the GoF form, the representation) | | Carries state between calls | no | no | yes — that is the point | | Handles many optional parts | poorly (parameter explosion) | poorly | yes | | Typical output | one product | several consistent products | one product, often immutable | | Enforces step order / cross-field rules | no | no | yes, in build() | The cleanest one-liner: **factories choose *what* to create; a builder governs *how* one thing is assembled.** ### Worked discrimination 1. *"An HTTP request has a URL plus a dozen optional things: headers, timeout, retries, body, proxy."* → **Builder.** No type choice at all; the difficulty is optionality and validation. 2. *"Depending on the file extension, return a `JsonParser`, `XmlParser` or `CsvParser` behind a `Parser` interface."* → **Factory Method** (or a static factory / registry). One call, one product, the concrete type hidden. 3. *"The UI must render entirely in the dark theme or entirely in the light theme, and every widget must match."* → **Abstract Factory.** The family-consistency guarantee is the whole requirement. 4. *"One traversal of an AST must emit either SQL or a Mongo filter."* → **GoF Builder** with a Director: same construction process, different representations. ### Common confusions to defuse - **"Builder is just a factory with more steps."** Misleading: a factory is stateless w.r.t. the product it makes, whereas the builder *is* the accumulating state. That state is what enables optionality, order enforcement, and whole-object validation. - **"Abstract Factory and Builder both create different products, so they're the same."** Abstract Factory switches families in a single call each; Builder assembles one product incrementally. Also, Abstract Factory's products share interfaces by design; GoF Builder's products need not share any supertype. - **Prototype** is the fourth creational neighbour: it creates by *cloning* an existing instance. If construction is expensive but a good template exists, Prototype (or a preconfigured builder used as a template, or a `withX()` copy method) may beat both. - **Singleton** answers "how many instances", an orthogonal question entirely. ### They compose, and that is normal - A static factory method returns the builder: `Report.builder()`. - `build()` may itself dispatch to a factory, choosing a concrete subclass based on the accumulated values (`if (streaming) new StreamingReport(...) else new BufferedReport(...)`) — a builder whose product type is polymorphic. - An Abstract Factory's methods may each return builders when the family members are themselves complex. In an interview, saying "they answer different questions and frequently appear together" is a stronger answer than forcing a single winner.
- Can a builder's build() return different concrete subclasses?Yes — build() can dispatch on the accumulated values and return, say, a streaming or a buffered implementation behind a shared interface. That is a builder collaborating with a factory decision; it does not turn it into Abstract Factory, which selects a whole family of related products rather than one product's implementation.
- Where does Prototype fit among these?Prototype creates by cloning a configured instance instead of assembling from scratch — useful when construction is expensive or when a good template already exists. It overlaps with reusing a preconfigured builder as a template, and with 'copy-with-one-field-changed' methods on immutable types.
- Is a static factory method like Duration.ofSeconds(30) a Factory Method in the GoF sense?Not strictly. GoF Factory Method is about letting subclasses decide the concrete class. A static factory method is a named, non-polymorphic alternative to a constructor — valuable for readability and caching, but it does not provide the subclass-driven variation point.
A vending machine (factory method) gives you a whole item for one selection; a themed furniture catalogue (abstract factory) guarantees the chair matches the table; a sandwich counter (builder) assembles one item from choices you make one after another.
saying these in an interview costs you the question
- Saying Builder and Abstract Factory are interchangeable because both 'create objects'
- Describing Builder purely as 'a factory with method chaining'
- Forgetting that Abstract Factory's core guarantee is consistency within a product family
- Treating a static factory method as identical to GoF Factory Method
- Insisting exactly one pattern must apply, when factories and builders routinely compose