Creational

Factory Method

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

Intermediate Pattern #02 of 23

What is the Factory Method Pattern?

Factory Method defines an interface for creating an object but lets subclasses decide which class to instantiate. Rather than calling new directly, you call a factory method that subclasses override to produce the right product type.

This pattern promotes loose coupling by eliminating the need to bind application-specific classes into your code — the code only deals with the product interface.

Real-world analogy: A logistics company (Creator) has a createTransport() method. A road logistics subclass returns a Truck; a sea logistics subclass returns a Ship. The high-level shipping logic stays the same — only the transport creation differs.

The Problem It Solves

Imagine you're building a UI library. You have a Dialog class that creates buttons. On Windows you need WindowsButton; on Mac you need MacButton. Hardcoding new WindowsButton() in Dialog couples it to a specific platform and makes extension painful.

You need a way to say "create a button" without specifying exactly which kind — letting platform-specific subclasses decide the concrete type.

Participants

Creator (abstract)
Declares the abstract factory method createProduct(). May contain core business logic that calls the factory method.
ConcreteCreator
Overrides createProduct() to return an instance of a specific ConcreteProduct.
Product (interface)
Defines the interface for objects the factory method creates.
ConcreteProduct
Implements the Product interface. The actual object that gets created.

Visual Flow Diagram

«abstract» Creator createProduct() WindowsDialog createProduct() WebDialog createProduct() «interface» Button render() / onClick() WindowsButton HTMLButton «creates» --- = inheritance/implements ··· = dependency

Java Code Example

Java
// Product interface
public interface Button {
    void render();
    void onClick();
}

// Concrete Products
public class WindowsButton implements Button {
    public void render() { System.out.println("Rendering Windows button"); }
    public void onClick() { System.out.println("Windows click handler"); }
}

public class HTMLButton implements Button {
    public void render() { System.out.println("Rendering HTML button"); }
    public void onClick() { System.out.println("HTML click handler"); }
}

// Creator — declares factory method
public abstract class Dialog {

    // The factory method — subclasses must implement
    public abstract Button createButton();

    // Uses the factory method — works with any Button
    public void renderDialog() {
        Button btn = createButton(); // polymorphic creation
        btn.render();
        btn.onClick();
    }
}

// Concrete Creators
public class WindowsDialog extends Dialog {
    public Button createButton() { return new WindowsButton(); }
}

public class WebDialog extends Dialog {
    public Button createButton() { return new HTMLButton(); }
}

// Client — works with Dialog abstraction, unaware of concrete type
public class Application {
    private static Dialog dialog;

    public static void main(String[] args) {
        String os = System.getProperty("os.name");
        if (os.contains("Windows")) {
            dialog = new WindowsDialog();
        } else {
            dialog = new WebDialog();
        }
        dialog.renderDialog(); // same call, different result
    }
}

When to Use / Avoid

✓ Use When

  • You don't know ahead of time what class you need to instantiate
  • You want subclasses to specify the objects they create
  • You need to encapsulate object creation and hide the concrete type from clients
  • Adding new product types should not require changing existing creator code

✕ Avoid When

  • Only one product type is ever needed — unnecessary complexity
  • The product type is unlikely to change
  • You prefer composition over inheritance — use Abstract Factory instead

Real-World Examples

Pros & Cons

Pros

  • Open/Closed Principle — add new products without changing creator
  • Single Responsibility — creation code in one place
  • Eliminates tight coupling between creator and concrete products

Cons

  • Requires subclassing — code can become more complex with many creators
  • Client must subclass Creator just to create a different product

How Factory Method Can Be Broken

⚠ Attack Vectors

  • Bypassing the factory: Client directly calls new WindowsButton() instead of dialog.createButton(), defeating the abstraction
  • Reflection: Client uses reflection to discover the concrete type and instantiate it directly, bypassing the intended polymorphism
  • Returning wrong type: A ConcreteCreator returns a product incompatible with the declared interface contract — violating Liskov Substitution Principle
  • Mutable product state leaks: If the factory returns a shared (non-new) instance, clients mutate shared state unexpectedly

✓ Prevention

  • Restrict direct instantiation: Make ConcreteProduct constructors package-private so clients outside the package can only get them through the factory
  • Program to interfaces: Clients should only reference the Button interface — never WindowsButton. Code reviews and architecture tests (ArchUnit) can enforce this
  • Contract tests: Write tests asserting that every ConcreteCreator's product correctly implements the Product interface behaviour
  • Return fresh instances: Factories should return new instances unless intentionally using caching — document the behaviour clearly
Java — Break & Fix
// ❌ BREAKING — client bypasses factory, couples to concrete class
Button btn = new WindowsButton(); // direct instantiation defeats the pattern

// ✅ FIX — restrict constructor visibility
class WindowsButton implements Button {
    // package-private — only WindowsDialog (same package) can instantiate
    WindowsButton() {}
    public void render() { /* ... */ }
    public void onClick() { /* ... */ }
}

// ❌ BREAKING — ConcreteCreator returns wrong type silently
public class BuggyDialog extends Dialog {
    public Button createButton() {
        return new HTMLButton(); // wrong platform — breaks visual consistency
    }
}

// ✅ FIX — ArchUnit test enforces factory usage (no direct instantiation)
// noClasses().that().resideInPackage("..client..")
//     .should().accessClassesThat().resideInPackage("..product.impl..")

How Other Patterns Relate

Interview Cheat Sheet

  1. What: Abstract method in a base class that subclasses override to return different product types — "let subclasses decide what to instantiate."
  2. How: Abstract Creator with abstract createProduct(). ConcreteCreators override it. Client calls the Creator's methods without knowing the concrete product.
  3. Key difference from Abstract Factory: Factory Method uses inheritance (one product per creator); Abstract Factory uses composition (families of products).