When would you choose Factory Method over Abstract Factory or Builder, and how do these three creational patterns differ?
answer
- one product vs. consistent family vs. assembly steps
- Abstract Factory = bag of factory methods
- new family easy, new product kind hard
- Builder = many optional parts, validate the whole
- inheritance (FM) vs. composition (AF)
basics
~20 sFactory Method varies one product through one overridable method. Abstract Factory groups several related products behind one interface so a whole family swaps together. Builder assembles one complex object step by step when it has many optional parts.
solid answer
~60 sAll three decouple callers from constructors, but along different axes. **Factory Method** — one overridable creation hook returning one product type; the variation point is inheritance on the creator. Choose it when a class's algorithm needs *one* collaborator whose concrete type varies by context, and the creator already exists for other reasons. **Abstract Factory** — an interface with several creation methods (`createButton()`, `createCheckbox()`); each concrete factory returns a mutually consistent *family*. Choose it when multiple products must vary together and mixing families would be a bug. Its methods are typically implemented as factory methods, which is why Abstract Factory is often described as "a bag of factory methods"; its weakness is that adding a *new product kind* changes the factory interface and every implementation. **Builder** — separates construction of one object from its representation, adding parts step by step and returning the result at the end. Choose it for many optional/required parameters, immutability, validation of the finished whole, or building different representations with the same steps — not for choosing among implementations. Rule of thumb: *which* class → Factory Method; *which consistent family* → Abstract Factory; *how to assemble one complicated instance* → Builder.
go deeper
Give the one-line intent of each and one example apiece; don't attempt the trade-off analysis.
Contrast the axes of variation clearly and note that Abstract Factory's methods are typically factory methods.
Drive the decision from constraints — consistency between products, parameter complexity, immutability/validation — and name the add-family-vs-add-product asymmetry and the inheritance-vs-composition distinction.
Discuss evolution paths (Factory Method → Abstract Factory → Prototype/registry), the expression-problem trade-off, how DI containers subsume much of this, and the cost of ceremony where no variation exists.
## Clean definitions | Pattern | Intent | Varies | Typical shape | |---|---|---|---| | **Factory Method** | Define an interface for creating an object; let subtypes decide which class to instantiate | One product, by creator subtype | `abstract createProduct(): Product` inside a creator that also holds logic | | **Abstract Factory** | Provide an interface for creating *families* of related or dependent objects without specifying concrete classes | A whole set, kept consistent | `interface UiFactory { createButton(); createCheckbox(); }` | | **Builder** | Separate the construction of a complex object from its representation, so the same process can create different representations | Assembly steps / optional parts | `b.withA().withB().build()` or a director driving steps | | *(context)* **Prototype** | Create objects by copying an existing instance | Which instance you clone | `original.copy()` | | *(context)* **Singleton** | Ensure one instance with global access | Instance count | Usually better replaced by DI-managed lifetime | ## Choosing between them ### Factory Method Signals: a class contains an algorithm that needs *one* collaborator; the concrete collaborator depends on context (environment, tenant, region, test vs. prod); you want to write the algorithm once. Costs: parallel Creator/Product hierarchies; extension requires subclassing, which is rigid and impossible if the creator is final/sealed or the variation must be chosen from runtime data. ### Abstract Factory Signals: **consistency constraints between products**. A Windows button with a macOS checkbox is not merely ugly, it's incorrect; a Postgres connection paired with an Oracle dialect object is broken. Abstract Factory makes mismatched combinations unrepresentable, because one factory instance yields the whole family. Costs: the well-known asymmetry — it's easy to add a new *family* (a new implementation class) but hard to add a new *product kind* (every existing factory implementation must implement the new method). This is the classic "expression problem" trade-off: you get extensibility along one dimension at the cost of the other. Mitigations include default methods on the interface or splitting into narrower factories (Interface Segregation). ### Builder Signals: a constructor with many parameters (especially many optional ones or several of the same type, where positional arguments get swapped silently); the object should be immutable once built; validation must run on the *complete* object, not per setter; or you construct a complex structure (a document, a query, an HTTP request) in steps. Builder is orthogonal to the other two — it answers "how do I assemble one instance?", not "which class do I instantiate?". They compose naturally: a factory method can *return* a fully configured object built by a Builder. Note the GoF Builder includes a **Director** that knows the construction sequence, so the same steps yield different representations (e.g. an HTML vs. plain-text rendering of the same document). The fluent "telescoping-constructor replacement" builder most codebases use is a simplified variant without a director. ## Relationships worth stating in an interview - Abstract Factory's methods are usually implemented *as* factory methods — the patterns nest rather than compete. - Factory Method uses **inheritance** to vary creation; Abstract Factory uses **object composition** (you hold a factory object). GoF explicitly notes designs often start with Factory Method and evolve toward Abstract Factory or Prototype as flexibility needs grow. - Prototype avoids a creator hierarchy entirely by cloning a registered exemplar — attractive when variants differ by *state* rather than by class, or when classes are created at runtime. - In systems with dependency injection, plain factory *interfaces* (or supplier/provider functions) often replace all of this: the container wires the right implementation, and you inject `Provider<Transport>` when you need lazy or repeated creation. ## Anti-patterns and edge cases - Stacking all three "because they're creational" produces ceremony with no decoupling gain. - Using Abstract Factory where products are independent: you get a rigid interface and no consistency benefit. - Using Builder where a couple of named parameters or a value object would do; conversely, keeping a 9-argument constructor because "a builder is boilerplate" trades a one-time cost for permanent call-site fragility. - Builders that expose `build()` without validating required fields defeat much of the purpose; the win is an object that cannot exist in an invalid state.
- Why is adding a new product kind to an Abstract Factory expensive, and how do you mitigate it?The product kind is a method on the factory interface, so every concrete factory must implement it — an O(number of families) change. Mitigations: default/no-op implementations on the interface, splitting into smaller focused factories, or moving to a registry keyed by product type when consistency between products isn't actually required.
- Can Builder and Factory Method be used together?Yes, and it's common: the factory method decides which concrete class to produce, and internally uses a builder to assemble it with validated, possibly immutable state. They address different questions — which type, versus how to assemble.
Factory Method is asking a branch office for "a vehicle". Abstract Factory is ordering a matched furniture set — sofa, chair, table all in the same style, so nothing clashes. Builder is a sandwich order: same counter, you choose bread, fillings, sauces, and only at the end do you get one finished sandwich.
saying these in an interview costs you the question
- Treating Factory Method and Abstract Factory as synonyms.
- Saying Builder is for choosing among implementations — it's for assembling one complex instance.
- Claiming Abstract Factory is strictly "better" because it's bigger; without a real consistency constraint it's just a rigid interface.
- Forgetting that Abstract Factory makes new product *kinds* expensive while new *families* are cheap.
- Adding a builder for a two-parameter object, or defending a nine-parameter constructor as "less boilerplate".