tech-docs

Living documentation for evolving technologies

View on GitHub

Abstract Factory Pattern


Table of Contents


The Abstract Factory is a formal GoF creational pattern that provides an interface for creating families of related objects without specifying their concrete classes. Where Factory Method varies creation along one product dimension through subclassing, Abstract Factory varies an entire product suite through composition — the client holds a factory interface and calls it to obtain a consistent set of products.


Overview

The motivation for Abstract Factory arises when a system must be independent of how its products are created and when those products belong to related families that must be used together. A cross-platform UI toolkit is the canonical example: a WinButton must pair with a WinCheckbox, never with a MacCheckbox. Abstract Factory enforces this constraint structurally.

The client is programmed entirely against factory and product interfaces. The concrete factory — WinFactory or MacFactory — is selected once (typically at startup) and injected into the client. From that point the client calls factory.createButton() and factory.createCheckbox() without ever knowing which platform-specific classes it receives.

Abstract Factory is the pattern behind javax.xml.parsers.DocumentBuilderFactory, the javax.sql.DataSource family, and Spring’s ApplicationContext which functions as an Abstract Factory and IoC container simultaneously.

Back to top


Participants

The Abstract Factory pattern defines five participants.

Back to top


Structure

classDiagram
    class GUIFactory {
        <<interface>>
        +createButton() Button
        +createCheckbox() Checkbox
    }
    class WinFactory {
        +createButton() Button
        +createCheckbox() Checkbox
    }
    class MacFactory {
        +createButton() Button
        +createCheckbox() Checkbox
    }
    class Button {
        <<interface>>
        +render() void
        +onClick() void
    }
    class Checkbox {
        <<interface>>
        +render() void
        +onCheck() void
    }
    class WinButton {
        +render() void
        +onClick() void
    }
    class MacButton {
        +render() void
        +onClick() void
    }
    class WinCheckbox {
        +render() void
        +onCheck() void
    }
    class MacCheckbox {
        +render() void
        +onCheck() void
    }
    class Client {
        -factory GUIFactory
        +Client(factory GUIFactory)
        +buildUI() void
    }

    GUIFactory <|.. WinFactory
    GUIFactory <|.. MacFactory
    Button <|.. WinButton
    Button <|.. MacButton
    Checkbox <|.. WinCheckbox
    Checkbox <|.. MacCheckbox
    WinFactory ..> WinButton : creates
    WinFactory ..> WinCheckbox : creates
    MacFactory ..> MacButton : creates
    MacFactory ..> MacCheckbox : creates
    Client --> GUIFactory : uses
    Client ..> Button : uses
    Client ..> Checkbox : uses

Caption: The Client is fully decoupled — it knows nothing about which platform-specific family it works with. Swapping WinFactory for MacFactory changes the entire product suite without touching any client code.

Back to top


Example

The following Java example shows the cross-platform GUI scenario from the diagram. The Application client is injected with a GUIFactory and calls it to build a consistent UI.

public interface Button   { void render(); }
public interface Checkbox { void render(); }

public class WinButton   implements Button   { public void render() { /* Win button   */ } }
public class WinCheckbox implements Checkbox { public void render() { /* Win checkbox */ } }
public class MacButton   implements Button   { public void render() { /* Mac button   */ } }
public class MacCheckbox implements Checkbox { public void render() { /* Mac checkbox */ } }

public interface GUIFactory {
    Button   createButton();
    Checkbox createCheckbox();
}

public class WinFactory implements GUIFactory {
    public Button   createButton()   { return new WinButton();   }
    public Checkbox createCheckbox() { return new WinCheckbox(); }
}

public class MacFactory implements GUIFactory {
    public Button   createButton()   { return new MacButton();   }
    public Checkbox createCheckbox() { return new MacCheckbox(); }
}

public class Application {
    private final Button   button;
    private final Checkbox checkbox;

    public Application(GUIFactory factory) {
        this.button   = factory.createButton();
        this.checkbox = factory.createCheckbox();
    }

    public void buildUI() { button.render(); checkbox.render(); }
}

Changing from Windows to Mac UI requires only swapping the factory instance passed to Application. No other code changes.

Back to top


Product Family Compatibility

Abstract Factory’s central guarantee is that all products returned by the same ConcreteFactory instance are designed to work together.

Back to top


Q&A

Common questions a software architect trainee would ask about this topic.

Q: What is the key difference between Factory Method and Abstract Factory? A: Factory Method uses inheritance — a subclass overrides a single factory method to return one product type. Abstract Factory uses composition — a client holds a factory interface that creates multiple related product types. Factory Method varies creation along one dimension; Abstract Factory varies an entire family.


Q: What guarantees does Abstract Factory provide about product compatibility? A: All products returned by the same concrete factory are guaranteed to be from the same family and designed to work together. Mixing products from different factories is prevented structurally because the client only ever interacts with one factory instance.


Q: When does Abstract Factory become the wrong choice? A: When a new product type (a new method on the AbstractFactory interface) needs to be added frequently. Every such addition forces changes across all concrete factory implementations. Abstract Factory is best suited for stable product families where the set of product types is fixed and only the variants change.


Q: Where does Abstract Factory appear in the Java ecosystem? A: javax.xml.parsers.DocumentBuilderFactory and javax.xml.transform.TransformerFactory are canonical examples — they abstract over different XML parser implementations. Spring’s ApplicationContext is a large-scale Abstract Factory / IoC container that produces beans of many types from a configured family of definitions.

Back to top


Back to top


Ref.


Get Started Factory Patterns