← Home
🏗Crack System Design with DSA AnimatorSystem DesignNEW
🏗 System Design›Creational Patterns

🏭Factory Method Pattern

Define an interface for creating an object — let subclasses decide which class to instantiate.

📌 Key IdeaHide new ConcreteProduct() behind a method (often on an abstract Creator). Clients call the method; which concrete product gets built is decided by which Creator subclass you use — not by if chains in the client.
✨

Why It Matters

  • Open/Closed — New product families extend by subclassing Creator, not editing callers.
  • Single creation choke-point — Logging, quotas, feature flags wrap one factory method.
  • Testing — Inject a test Creator that returns stubs — no static new in domain logic.
💡

In Layman's Terms

A pizza chain does not ask every customer to knead dough in the kitchen. Each franchise (concrete creator) knows how to make its local pizza (product) — the menu (client) just says "one pizza please".

Factory Method is that hook: something else owns the recipe for construction so your ordering code stays the same when you add Chicago vs NY style.

🌍

Real-World Analogy

🍕 Franchise kitchen

Corporate defines interface OrderPizza() and what happens after (box, slice). Each store implements how the actual pizza is constructed — deep dish vs thin crust.

Adding a new regional style means new subclass, not editing every kiosk's code.

🖼

Visual

❌ Client picks concrete class
Every new product type → edit the client.
  class ReportApp {
    void run(String format) {
        Document doc;
        if (format.equals("pdf"))  doc = new PdfDocument();
        else if (format.equals("html")) doc = new HtmlDocument();
        // +markdown? change this file again
        doc.render();
    }
  }
✅ Creator defers to factory method
New format = new Creator subclass — client stable.
  abstract class ReportCreator {
      abstract Document createDocument();
      void export() { createDocument().render(); }
  }
  class PdfReportCreator extends ReportCreator {
      Document createDocument() { return new PdfDocument(); }
  }
🧱 GoF structure (simplified)
Creator.templateMethod() calls abstract factoryMethod().
  ┌──────────────┐         ┌──────────────┐
  │   Creator    │────────▶│   Product    │◀──┐
  ├──────────────┤  creates└──────────────┘   │
  │+ factoryM()  │         ▲                 │
  │+ business()  │         │                 │
  └──────┬───────┘         │                 │
         │                 │                 │
    ┌────┴────┐      ┌────┴─────┐     ┌─────┴──────┐
    │Concrete │      │Concrete  │     │ Concrete   │
    │Creator A│      │Product A │     │ Product B   │
    └─────────┘      └──────────┘     └────────────┘

Top — central if/switch vs subclass-owned creation. Bottom — Creator/Product parallel hierarchies.

✅

When to Use

  • The exact type of product cannot be known until runtime or varies by deployment / plugin.
  • Framework defines skeleton (template method); app supplies concrete products.
  • You want parallel hierarchies — each product variant has a matching creator variant.
  • You are tired of `new` sprinkled through UI/services — centralise construction.
🚫

When NOT to Use

  • Only one concrete product exists forever — a plain constructor or DI @Bean is enough.
  • You need families of related products together (PDF + Parser + Validator) — consider Abstract Factory.
  • Object graphs are huge and step-built — Builder fits better.
🚨

Anti-Pattern (What NOT to Do)

Client owns product selectionBadjava
public final class UiExporter {

    public void saveAs(User user, String ext) {
        Document doc;
        switch (ext) {
            case "pdf"  -> doc = new PdfDocument(user);
            case "docx" -> doc = new DocxDocument(user);
            default     -> throw new IllegalArgumentException(ext);
        }
        doc.write(Path.of("out." + ext));
    }
}
Adding Markdown touches UiExporter and every caller path — tight coupling to concrete classes.
✅

The Right Way

Creator subclasses supply productsGoodjava
public interface ExportCreator {
    Document create(User user);
}

public final class PdfExportCreator implements ExportCreator {
    public Document create(User user) { return new PdfDocument(user); }
}

public final class ExportDialog {
    private final ExportCreator creator;

    public ExportDialog(ExportCreator creator) { this.creator = creator; }

    public void save(User user, Path out) {
        creator.create(user).write(out);  // stable — swap creator impl
    }
}
UI depends on ExportCreator, not on PdfDocument. New format = new class implementing ExportCreator.
⚖️

Pros & Cons

👍 Pros
  • Decouples client from concrete product classes.
  • Aligns with Template Method — Creator often implements algorithm skeleton.
  • Natural fit for plugins — load Creator implementation per configuration.
👎 Cons
  • Two parallel hierarchies can feel heavy for small apps.
  • Indirection — readers jump Creator → Product to understand wiring.
  • Overkill when only one implementation exists.
📊

Factory Method vs neighbours

AspectFactory MethodAbstract FactorySimple factory (idiom)
ScopeOne product kind per CreatorFamilies of related productsOne method + switch/registry
ExtensionSubclass CreatorNew concrete factoryEdit method or registry
GoF pattern?YesYesNo (idiom / helper)
Typical painParallel hierarchies growMany interfaces at onceGod method grows
🔀

Common Confusions Cleared Up

Factory Method vs Constructor

Constructors only build their class. Factory Method returns a supertype and can hide subclasses, caching, pooling, or remote proxies.

Factory Method vs Builder

Factory Method chooses which class to build in one shot. Builder assembles one complex object step-by-step with many optional parts.

🧪

Variations / Implementations

1️⃣ Classic GoF

Abstract factoryMethod() on Creator; each concrete Creator returns one Product type.

Subclass decidesjava
abstract class Dialog {
    abstract Button createButton();   // factory method
    void render() {
        Button b = createButton();
        b.paint();
    }
}

class WinDialog extends Dialog {
    Button createButton() { return new WinButton(); }
}
Framework (Dialog) stays fixed; platform-specific button comes from subclass.

2️⃣ Parameterized factory (simple factory)

One method takes a key — often not listed as a separate GoF pattern but common in apps.

Registry lookupjava
Document create(String type, User u) {
    return registry.get(type).apply(u);  // Map<String, Function<User,Document>>
}
Use when variants are data-driven; watch OCP — new keys may still need registry edits.

3️⃣ Spring-style injection

@Bean methods are factory methods — container calls them to produce singleton/prototype beans.

@Configuration factoryjava
@Configuration
class AppConfig {
    @Bean
    PaymentClient paymentClient(PaymentProps p) {
        return PaymentClient.connect(p.getUrl());
    }
}
Same idea: creation centralized; wiring lives in one place.
⚠️

Common Mistakes / Anti-Patterns

  • Naming every static create() "factory method" — the pattern is about polymorphic creation, not static helpers alone.
  • God class with createEverything(type) and 40-case switch.
  • Returning null from factory — prefer Optional or exception.
🎤

Interview Q&A

🔮

Likely Follow-up Questions

  • Sketch Template Method + Factory Method together on a DataExporter.
  • How does Supplier<T> in Java 8 mirror Factory Method?
  • When does a parameterized factory violate Open/Closed?
  • Compare Factory Method with Prototype pattern.
🧾

Quick Cheat Sheet

IntentDefer instantiation to a method; subclasses choose type.
StructureCreator.factoryMethod() → Product.
vs Abstract FactoryOne product hierarchy vs product families.
SmellHuge switch (type) in UI layer.
Java hook@Bean, Supplier, SPI services.
🔗

Related Topics