How do Factory Method and Abstract Factory differ in intent and structure, and how do you decide which one a design needs?
answer
- Factory Method = one method, subclass decides, inheritance
- Abstract Factory = one object, many methods, family consistency, delegation
- count creation methods to tell them apart
- new family cheap / new product kind expensive (Abstract Factory)
- Abstract Factory methods are often Factory Methods
basics
~20 sFactory Method is one overridable method on a class; a subclass decides which single product to create. Abstract Factory is a separate object with several creation methods that produce a whole family of related products that must match each other.
solid answer
~50 s**Factory Method**: a class that uses a product declares an abstract/overridable creation method (`createProduct()`) and calls it from its own logic. Subclasses override it to choose the concrete product. Variation comes from **inheritance**, and it is bound when you pick the subclass — typically one product type per creator. **Abstract Factory**: an interface with **multiple** creation methods (`createButton()`, `createScrollbar()`, `createMenu()`), each concrete factory implementing one consistent **family** (Dark theme, Light theme). The client holds a factory object and asks it for parts. Variation comes from **delegation/composition**, and it is swappable at runtime by handing over a different factory. Decide by counting product types and asking whether they must be consistent. One product kind, and the choice belongs to a subclass of the code that uses it → Factory Method. Several product kinds that must come from the same family, and you want to swap the whole set at once → Abstract Factory. In practice Abstract Factory implementations often use Factory Methods internally for each product.
code
pseudocode · 11 lines// Factory Method: variation by SUBCLASSING the consumer
abstract class Report {
abstract createRenderer(): Renderer // one overridable step
print() { createRenderer().render(this) }
}
class PdfReport : Report { createRenderer() = PdfRenderer() }
// Abstract Factory: variation by SWAPPING an injected object
interface Toolkit { createButton(): Button; createDialog(): Dialog }
class Screen(t: Toolkit) { open() { t.createDialog().add(t.createButton()) } }
// Screen(DarkToolkit()) can never mix a dark dialog with a light buttongo deeper
Say Factory Method is one overridable creation method that a subclass implements; Abstract Factory is an object with several creation methods that produce a matching set.
Add the inheritance-vs-delegation distinction, give an example of each, and note that swapping the family at runtime is natural only with Abstract Factory.
Discuss the family-consistency invariant as the real reason to pay for Abstract Factory, the Open/Closed asymmetry (new family cheap, new product kind expensive), and when a DI container makes both unnecessary.
Frame it as where the system's variation seams belong and who owns the binding decision (framework extension point vs deployment configuration), plus the long-term maintenance cost of factory interfaces that grow product kinds.
## Vocabulary - **Product** — the object being created (e.g. a `Button`). - **Creator / Factory** — the thing responsible for producing products. - **Family** — a set of products designed to be used together (all `Dark` widgets; all `PostgreSQL` DAOs). ## Factory Method — "let the subclass decide" Structure: ``` abstract class Dialog { abstract fun createButton(): Button // the factory method fun render() { // template logic that USES the product val b = createButton() b.onClick { close() } draw(b) } } class WindowsDialog : Dialog { override fun createButton() = WindowsButton() } class WebDialog : Dialog { override fun createButton() = HtmlButton() } ``` Key traits: - The creation method **lives on the class that consumes the product**. `Dialog` both creates and uses the button. - Variation is via **inheritance**: to change the product you instantiate a different subclass. That binding is made once, where you choose the subclass. - Usually **one product** (or a small number) per creator. - Very often paired with **Template Method**: a fixed algorithm in the base class calls the overridable creation step. - Also called the *virtual constructor*. When it fits: a framework defines the workflow but cannot know the concrete type; extension happens by subclassing (`Application.createDocument()`, a `Collection.iterator()` returning the right iterator type). ## Abstract Factory — "a family that matches" Structure: ``` interface GuiFactory { fun createButton(): Button fun createScrollbar(): Scrollbar fun createMenu(): Menu } class DarkFactory : GuiFactory { /* returns DarkButton, DarkScrollbar, DarkMenu */ } class LightFactory : GuiFactory { /* returns LightButton, LightScrollbar, LightMenu */ } class Screen(private val factory: GuiFactory) { // holds a factory, does not subclass fun build() { factory.createButton(); factory.createScrollbar() } } ``` Key traits: - The factory is a **separate object** the client is *given* (constructor injection, config, DI container). - **Multiple creation methods**, one per product kind — that is the visible structural difference. - The enforced invariant is **consistency**: it is impossible to mix a `DarkButton` with a `LightScrollbar`, because one factory only makes one family. - Variation is via **composition**, so the family can be swapped **at runtime** by assigning a different factory instance. When it fits: cross-platform UI toolkits, database-vendor-specific DAO sets, environment-specific service bundles (real vs sandbox payment gateway + ledger + notifier), theming. ## Head-to-head | | Factory Method | Abstract Factory | |---|---|---| | GoF category | class creational (inheritance) | object creational (delegation) | | Number of creation methods | one (per product) | many (one per product kind) | | Who holds the creation logic | the class that uses the product, via subclass | a distinct factory object | | How you switch | instantiate a different subclass | pass a different factory object | | Switch at runtime | awkward (already bound to a subclass) | natural (swap the reference) | | Core invariant | "the right concrete product for this creator" | "all products come from one consistent family" | | Typical relationship | often used *inside* an Abstract Factory's methods | often built *from* Factory Methods | ## Choosing — a decision procedure 1. **How many product kinds vary together?** One → Factory Method. Several that must be mutually compatible → Abstract Factory. 2. **Is there a family-consistency bug you must make impossible?** (mixing a Postgres connection with a MySQL dialect). If yes → Abstract Factory; the type system then prevents the mismatch. 3. **Does the creation choice belong to a subclass of the consumer, or to the caller/configuration?** Subclass → Factory Method. Caller/config → Abstract Factory. 4. **Must the choice change while the program runs?** Yes → Abstract Factory (or a plain factory object); Factory Method binds when you choose the subclass. ## Edge cases and common confusions - **"Simple/static factory" is neither.** A `static create(type)` with a switch is a useful idiom but not a GoF pattern; it centralizes creation without polymorphic extension. - **Adding a new product kind** to an Abstract Factory is expensive: the interface gains a method and **every** concrete factory must implement it (the classic Open/Closed tension — easy to add a family, hard to add a product kind). - **Adding a new family** is cheap for Abstract Factory: one new class. - **Degenerate Abstract Factory** with a single creation method is really just a factory object; do not call it Abstract Factory for status. - **DI containers subsume much of this**: registering `GuiFactory -> DarkFactory` in a profile achieves the same family swap without hand-written factory classes.
- You have an Abstract Factory with five concrete factories and must add a sixth product kind. What breaks, and how do you mitigate it?The factory interface gains a method, so all five concrete factories must implement it — a violation of Open/Closed in the 'add a product kind' direction. Mitigations: a default implementation in the interface/abstract base, splitting the interface so clients depend only on what they use (Interface Segregation), or replacing hand-written factories with DI registrations keyed by product type.
- Is a class with a `static create(String type)` and a switch statement a Factory Method?No. That is the 'simple factory' or 'static factory method' idiom. GoF Factory Method requires an overridable instance method whose implementation is supplied by a subclass; a static switch cannot be polymorphically extended and must be edited for every new type.
- How does a dependency-injection container change this decision?It absorbs most of it. Binding an abstract type to a concrete implementation per profile/environment gives family swapping without writing factory classes. Hand-written factories remain justified when creation needs runtime arguments the container does not have, when the family invariant should be visible in the type system, or when you need creation on demand rather than at injection time.
Factory Method is a recipe with one blank step that each branch of a restaurant chain fills in its own way. Abstract Factory is a whole supplier contract: you sign with the Italian supplier and every ingredient — pasta, cheese, oil — arrives from that one consistent catalogue.
saying these in an interview costs you the question
- Calling any class named `SomethingFactory` an Abstract Factory
- Saying the difference is 'Abstract Factory is abstract and Factory Method is concrete' — both involve abstraction; the difference is inheritance-vs-delegation and one product vs a family
- Claiming Abstract Factory makes adding new product types easy — it makes adding new *families* easy and new *product kinds* costly
- Introducing an Abstract Factory when there is exactly one family and no second one on the horizon
- Missing that the client of an Abstract Factory must not know the concrete factory class — otherwise the decoupling is lost