Factory Method vs Abstract Factory — when to use each? — Cracked Java
// Object-Oriented Programming · Creational Design Patterns
MidTheoryEPAM

Factory Method vs Abstract Factory — when to use each?

Factory Method creates one product through a method that subclasses override; Abstract Factory creates a family of related products through a separate factory object. The distinguishing axis is whether the variation is along one product type (Factory Method) or across multiple coordinated product types (Abstract Factory). Confuse them at your peril — they look similar in code but solve different design problems.

Factory Method — one product, subclass decides

The pattern: a base class defines a method that returns a product. Subclasses override the method to return their flavor of the product.

public abstract class Logger {
    public final void log(String msg) {
        Formatter f = createFormatter();         // factory method
        System.out.println(f.format(msg));
    }
    protected abstract Formatter createFormatter();
}

public class JsonLogger extends Logger {
    @Override protected Formatter createFormatter() { return new JsonFormatter(); }
}
public class TextLogger extends Logger {
    @Override protected Formatter createFormatter() { return new TextFormatter(); }
}

The base class's algorithm (log) is fixed. The type of one collaborator (the formatter) is decided by the subclass. Classic Template Method + Factory Method combo.

When to use:

  • A framework defines a workflow but lets clients plug in the concrete type.
  • The product type varies along a single axis you can express as a class hierarchy.

Java JDK examples:

  • Collection.iterator() — every collection overrides to return its own iterator type.
  • URLStreamHandlerFactory.createURLStreamHandler(String protocol).

Abstract Factory — a family of products

The pattern: an interface declares methods to create several related products. Each concrete factory implementation produces a coordinated set.

public interface UiFactory {
    Button createButton();
    Menu   createMenu();
    Window createWindow();
}

public class MacUiFactory implements UiFactory {
    public Button createButton() { return new MacButton(); }
    public Menu   createMenu()   { return new MacMenu(); }
    public Window createWindow() { return new MacWindow(); }
}
public class WindowsUiFactory implements UiFactory {
    public Button createButton() { return new WinButton(); }
    public Menu   createMenu()   { return new WinMenu(); }
    public Window createWindow() { return new WinWindow(); }
}

// Client
public class App {
    private final UiFactory ui;
    public App(UiFactory ui) { this.ui = ui; }
    public void render() {
        ui.createWindow().add(ui.createMenu());
        ui.createWindow().add(ui.createButton());
        // Guaranteed: all Mac or all Windows — can never mix
    }
}

The family invariant is the point. App can never accidentally pair a MacButton with a WinWindow — the factory enforces consistency.

When to use:

  • Multiple product types must vary together.
  • Cross-cutting variations (look-and-feel themes, database flavors, cloud providers).

Java JDK examples:

  • DocumentBuilderFactory + DocumentBuilder + Document — though it's also a static-factory style.
  • javax.xml.transform.TransformerFactory and its product Transformer.

The structural diagram

Factory Method:                    Abstract Factory:

Logger                              UiFactory
  | createFormatter()                | createButton()
  |                                  | createMenu()
 /+\                                | createWindow()
JsonL TextL                          /+\
 |     |                          MacUiF WinUiF
JsonF  TextF                       /|\   /|\
                                MacButton, MacMenu, ...
Factory Method vs Abstract Factory

How to choose

Ask: does the variation cross multiple product types that must stay consistent?

  • Yes → Abstract Factory. You need the family invariant.
  • No, just one product type varying → Factory Method (or a static factory method if subclassing is overkill).

A modern twist

Both patterns predate generics and lambdas. In modern Java, a Supplier<T> parameter often replaces Factory Method for the single-product case:

public class Logger {
    private final Supplier<Formatter> formatterFactory;
    public Logger(Supplier<Formatter> f) { this.formatterFactory = f; }
    public void log(String msg) { System.out.println(formatterFactory.get().format(msg)); }
}

new Logger(JsonFormatter::new).log("hi");

No subclass needed; the "factory" is a method reference. Abstract Factory still pays off when there are multiple coordinated products.

Mark your status