7 min read
Object-Oriented Design Index
Tier 1 -- Foundations
Core Concepts
SOLID Principles
Creational Patterns
Structural Patterns
Tier 2
Tier 3
Tier 4
Tier 5
Object-Oriented Design Index
Tier 1 -- Foundations
Core Concepts
SOLID Principles
Creational Patterns
Structural Patterns
Tier 2
Tier 3
Tier 4
Tier 5
Factory Method Pattern
1. What Is It?
The Method pattern defines an for creating an object but lets subclasses decide which concrete class to instantiate. Rather than calling new ConcreteProduct() directly in your business logic, you call an abstract create() method — and each subclass provides the actual instantiation. The creator class can then operate on the product through its without knowing or caring about the specific type it received.
Without this pattern, client code that needs to create objects becomes littered with if/else or switch blocks that must be updated every time a new type is added. This violates the Open/Closed Principle: the existing creation logic must be modified to support extension. Method isolates that variation point in a dedicated override.
A payment processing service currently supports credit card and PayPal payments using a large switch statement in the checkout logic. Every time a new payment method is added, a developer must modify that switch statement. Which problem does this design exhibit, and how does the Factory Method pattern address it?
2. How It Works
Step-by-step mechanics:
- Define a
Productwith the operations all product variants must support. - Implement
ConcreteProductclasses for each variant. - Define a
Creator(or ) with an abstractfactory_method()that returnsProduct. - Put the core business logic in
Creator— it usesfactory_method()to get a product but never knows the concrete type. - Create
ConcreteCreatorsubclasses that each overridefactory_method()to return a specificConcreteProduct.
Python
from abc import ABC, abstractmethod from typing import Protocol class Button(Protocol): """Interface all button types must satisfy.""" def render(self) -> None: ... def on_click(self, handler: callable) -> None: ... class HtmlButton: def render(self) -> None: print("<button>Click me</button>") def on_click(self, handler: callable) -> None: print(f"Bound JS handler: {handler.__name__}") class WindowsButton: def render(self) -> None: print("[Win32 Button: Click me]") def on_click(self, handler: callable) -> None: print(f"Registered Win32 callback: {handler.__name__}") class Dialog(ABC): """Creator — contains the core business logic; delegates creation to subclasses.""" @abstractmethod def create_button(self) -> Button: """Factory method — subclasses decide which button type to produce.""" ... def render_window(self) -> None: button = self.create_button() # uses the product via the interface button.render() class HtmlDialog(Dialog): def create_button(self) -> Button: return HtmlButton() class WindowsDialog(Dialog): def create_button(self) -> Button: return WindowsButton() def build_dialog(os_type: str) -> Dialog: """Client code — picks a ConcreteCreator based on configuration.""" creators: dict[str, type[Dialog]] = { "web": HtmlDialog, "windows": WindowsDialog, } creator_class = creators.get(os_type) if creator_class is None: raise ValueError(f"Unknown OS type: {os_type}") return creator_class() dialog = build_dialog("web") dialog.render_window() # <button>Click me</button>
Java
// Product interface public interface Button { void render(); void onClick(Runnable handler); } // Concrete products public class HtmlButton implements Button { @Override public void render() { System.out.println("<button>Click me</button>"); } @Override public void onClick(Runnable handler) { System.out.println("Bound JS handler"); handler.run(); } } public class WindowsButton implements Button { @Override public void render() { System.out.println("[Win32 Button: Click me]"); } @Override public void onClick(Runnable handler) { System.out.println("Registered Win32 callback"); handler.run(); } } // Creator — abstract class with the factory method hook public abstract class Dialog { // Factory method — subclasses override this public abstract Button createButton(); // Core business logic uses the product via the interface public void renderWindow() { Button button = createButton(); button.render(); } } // Concrete creators public class HtmlDialog extends Dialog { @Override public Button createButton() { return new HtmlButton(); } } public class WindowsDialog extends Dialog { @Override public Button createButton() { return new WindowsButton(); } } // Client public class Application { public static Dialog configure(String osType) { return switch (osType) { case "web" -> new HtmlDialog(); case "windows" -> new WindowsDialog(); default -> throw new IllegalArgumentException("Unknown OS: " + osType); }; } public static void main(String[] args) { Dialog dialog = configure("web"); dialog.renderWindow(); // <button>Click me</button> } }
In a Factory Method pattern, the abstract Dialog class contains a render_window() method that calls self.create_button() internally. Why does Dialog call its own factory method rather than directly instantiating a specific button class like HtmlButton?
3. Variants & Comparisons
| Approach | How It Works | Pros | Cons | Best For |
|---|---|---|---|---|
| Factory Method | Subclass overrides one creation hook | Simple; single product; follows inheritance hierarchy | One new class per variant | When subclassing is already occurring |
| Abstract Factory | Separate factory object creates a family of related products | Consistent product families; no subclassing required | More classes; harder to extend with new products | When products must be used together (e.g., UI theme) |
| Static Factory Method | static method returns instances (not GoF) | Convenient; can return cached/subtype instances | Not overridable; less polymorphic | Utility creation (Optional.of, List.of) |
| Simple Factory (not GoF) | One class with a create(type) switch | Easy to understand | Violates OCP; grows indefinitely | Throwaway prototypes |
Designs often start with Method and evolve into Abstract when multiple coordinated product families are needed.
A frontend team is building a design system that supports multiple UI themes (e.g., Light and Dark). Each theme requires a consistent set of coordinated components — buttons, modals, and tooltips — that must all match the same theme. Which factory pattern variant is the best fit, and why?
4. When to Use It (and When NOT To)
Use Method when:
- A class cannot anticipate the type of objects it needs to create.
- Subclasses should control which concrete product is instantiated.
- You want to isolate product-creation logic so that adding a new product type requires only one new class, not touching existing ones.
Do NOT use Method when:
- You only have one product type that will never vary — it adds unnecessary indirection.
- The variation is configuration-driven (a dictionary/map lookup is simpler).
- You need to create families of related products — use Abstract Factory instead.
Anti-patterns:
- Factory everywhere — applying Factory Method to every class adds classes without benefit when the creation logic is trivial.
- Creator doing too much — the Creator class should contain business logic that uses the product; if it's just a creation class, consider using a simple factory function.
Decision triggers:
- "I have a base class whose subclasses should vary the type of object created" → Factory Method
- "I need to add new product types without modifying existing code" → Factory Method satisfies OCP here
- "I need consistent sets of related objects (e.g., all Windows widgets or all Mac widgets)" → Abstract Factory
A backend team is building a notification service that currently sends only email alerts. The team is certain it will need to add SMS, push notifications, and Slack messages over the next few months, each requiring different initialization logic. A junior developer suggests using the Factory Method pattern. A senior developer pushes back, saying the variation is purely configuration-driven and a map lookup would be simpler. Which scenario would most strongly justify the junior developer's position and make Factory Method the better choice?
5. Real-World Usage
Java java.util.Calendar.getInstance()
This is a static method that returns a locale- and timezone-appropriate Calendar subclass. The caller never instantiates Calendar directly — the method selects the right concrete implementation (GregorianCalendar, JapaneseImperialCalendar, etc.) based on the system locale. This is the Factory Method intent applied at a static level.
javax.xml.parsers.DocumentBuilderFactory
DocumentBuilderFactory.newInstance() returns a platform-specific factory, and factory.newDocumentBuilder() is the factory method that produces a DocumentBuilder. This decouples client XML-parsing code from any specific parser implementation (Xerces, JDK built-in, etc.).
Python unittest framework
unittest.TestLoader.loadTestsFromTestCase() acts as a factory method that creates TestSuite objects. Subclassing TestLoader and overriding loadTests* methods lets frameworks customize how tests are collected — a real-world application of the Factory Method hook.
Your team is building an XML processing service that must run on multiple platforms, each with a different underlying parser implementation. You want client code to remain completely decoupled from any specific parser. Which design approach best matches how javax.xml.parsers.DocumentBuilderFactory solves this same problem?
6. Interview Cheat Sheet
Key sentences to demonstrate depth:
- " Method doesn't just move
newto another place — the key insight is that the Creator contains real business logic that operates on the product through an , making the creation variation a hook, not the whole point." - "Every time you add a new product type, you add one new
ConcreteCreatorsubclass. The existingCreatorand all otherConcreteCreatorsare untouched — this is the Open/Closed Principle in action." - "The difference between Method and Abstract Factory is vs. : Factory Method uses subclass overrides to vary the product; Abstract Factory uses a separate factory object to create a consistent family of products."
- "Static factory methods like
Optional.of()share the name but not the pattern — they can't be overridden, so you can't use to vary the product type."
Common follow-up questions:
- "When would you use Abstract Factory instead?" → When you need to ensure a family of related objects are used together (e.g., a UI toolkit where buttons, dialogs, and checkboxes must all match the same platform theme).
- "How is this different from just a constructor?" → A factory method can return a subtype, return a cached instance, have a descriptive name, and be overridden in subclasses — none of which a constructor can do.
- "What's the Open/Closed connection?" → New product types require new subclasses, not changes to existing code. The base Creator class is closed for modification but open for extension.
Connections to other concepts:
- — Factory Method is often a special case of where the hook method creates an object rather than performing a step.
- Abstract Factory — a natural evolution when multiple related product types need to be coordinated.
- — Factory Method breaks the direct dependency on
ConcreteProductby having the Creator depend only on theProduct.
Glossary History
Click dotted jargon to save explanations here.
Glossary History
Click dotted jargon to save explanations here.