Design Patterns: Creational · Creational Patterns

Abstract Factory Pattern

Producing a whole family of related objects together, guaranteed to be mutually compatible.

  • 5 min read
  • 11 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The pattern
  3. Where you'll see it
  4. Choosing among the creational patterns
  5. Common mistakes
  6. Check yourself
  7. Key takeaways
  8. Quick revise
  9. Practice

Description

Abstract Factory is the creational pattern for families of objects that must match - all dark-theme widgets or all light-theme ones, all PostgreSQL objects or all MySQL ones. Instead of deciding "which family?" every time an object is created, you choose one factory once, and everything it creates belongs to the same family. This skill covers the pattern, how it relates to Factory Method, and the one kind of change it makes expensive.

A UI supports a dark and a light theme, and every screen builds its own widgets:

Java

Button ok = dark ? new DarkButton() : new LightButton();
Checkbox remember = dark ? new DarkCheckbox() : new LightCheckbox();
TextField name = new LightTextField();   // someone forgot the check

Python

ok = DarkButton() if dark else LightButton()
remember = DarkCheckbox() if dark else LightCheckbox()
name = LightTextField()   # someone forgot the check

Every widget repeats the same decision, and one forgotten check puts a light text field on a dark screen. A choice that should be made once - "which theme?" - is made dozens of times, separately for each product.

We'll go from simple to more technical:

  1. The pattern: one factory object with a creation method per product.
  2. Where you'll see it: UI toolkits, database drivers, environment-specific setups.
  3. Which changes it makes cheap (a new family) and which it makes expensive (a new product).
  4. Choosing among the creational patterns.

The pattern

Java

interface UIFactory {
    Button createButton();
    Checkbox createCheckbox();
}
class WindowsUIFactory implements UIFactory { /* ... */ }
class MacUIFactory implements UIFactory { /* ... */ }

// caller picks ONE factory instance, then every widget it produces matches:
UIFactory factory = isMac ? new MacUIFactory() : new WindowsUIFactory();
Button b = factory.createButton();
Checkbox c = factory.createCheckbox(); // guaranteed same theme as b

Python

from abc import ABC, abstractmethod


class UIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: ...

    @abstractmethod
    def create_checkbox(self) -> Checkbox: ...


class WindowsUIFactory(UIFactory): ...
class MacUIFactory(UIFactory): ...


# caller picks ONE factory instance, then every widget it produces matches:
factory = MacUIFactory() if is_mac else WindowsUIFactory()
b = factory.create_button()
c = factory.create_checkbox()   # guaranteed same theme as b

Each createX() method is itself a factory method. Abstract Factory groups them on one object, so the whole family is chosen by a single decision - which factory you hand out.

Where you'll see it

Cross-platform UI toolkits and database-vendor abstraction layers (a factory that produces a matched Connection, Statement, and ResultSet implementation set for whichever vendor is configured) both need this "everything from one factory is guaranteed compatible" property. In Python, a DB-API driver module plays that role: the connection psycopg.connect() returns makes cursors of its own family, and code written against the DB-API works with any driver.

Choosing among the creational patterns

If you need...Reach forBecause
Exactly one shared instance, by designSingletonTwo copies would be a bug (e.g. two connection pools fighting over the same database connections).
One place that decides which concrete class to buildFactory MethodCallers depend on an interface; adding a type changes the factory, not every caller.
A matched family of related objects that must vary togetherAbstract Factory (this lesson)Swapping the factory swaps the whole family, so mismatched pieces can't be combined.
An object with many optional parts, assembled step by stepBuilderNamed, optional steps instead of long positional constructors; validate once in build().
Many near-identical objects that are expensive to set upPrototypeCopy a ready-made template instead of repeating costly construction.

Common mistakes

MistakeWhat happensDo this instead
An Abstract Factory for a single product typea "family" of one - extra structure, no benefita simple factory or Factory Method
Choosing the family in many placesthe mismatch bug comes backchoose the factory once, at startup or from configuration
Creating two factories and mixing their productsa dark button on a light screenpass one factory around; let code ask only it
Expecting new products to be cheapevery factory must implement the new methodexpect it, or give the new method a default
Hand-written factory hierarchies duplicating DI profilestwo mechanisms for one choicelet the container select the family per environment

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. You add a third theme (high contrast), and later a new widget (Slider). What changes each time?

Show answer

The theme: one new factory class, nothing else. The widget: the factory interface gains createSlider(), and every existing factory must implement it.

2. The app only has buttons - no checkboxes, no other widgets. Abstract Factory?

Show answer

No. With one product there is no family to keep consistent; a simple factory (or no factory at all) is enough.

3. Where does the "which theme?" decision live once you use an Abstract Factory?

Show answer

In one place: wherever the factory is chosen, often at startup or from configuration. Every screen just uses the factory it is given.

Key takeaways

  • It creates families of related objects that must match (all dark-theme, or all light-theme).
  • Client code talks only to the factory and product interfaces, so it cannot mix families by accident.
  • Adding a new family is easy (one new factory class); adding a new product type touches every factory.
  • With only one product type there is no family to protect - a plain Factory Method is enough.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
Several related products that must matchAbstract Factory
One product, chosen by data or subclassFactory Method / simple factory
A matched set per environment in a DI appcontainer profiles
A family chosen per request or tenantresolve the factory once at the edge, pass it down
A matched fake set for testsan in-memory factory, checked by contract tests

Snippets worth knowing by heart

Java

interface UIFactory {
    Button createButton();
    Checkbox createCheckbox();
    default Slider createSlider() { return new PlainSlider(); }   // a new product without breaking families
}

UIFactory factory = config.darkMode() ? new DarkUIFactory() : new LightUIFactory();
Screen screen = new Screen(factory);   // the screen asks only this factory

Python

class UIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button: ...

    @abstractmethod
    def create_checkbox(self) -> Checkbox: ...

    def create_slider(self) -> Slider:     # a new product without breaking families
        return PlainSlider()

factory = DarkUIFactory() if config.dark_mode else LightUIFactory()
screen = Screen(factory)

The traps

  • A family of one - just use a factory.
  • Choosing the family in many places - the mismatch returns.
  • Two factories in one place - products get mixed.
  • Expecting new products to be cheap - they touch every factory.

Staff-level points, one line each

  • The guarantee is by convention; package-private constructors or generic family types make mixing impossible.
  • <T extends Theme> screen(Button<T>, Checkbox<T>) turned a dark/light mix into a compile error.
  • New families are one class; new products break every factory (Java compile error, Python abstract class) - defaults soften it.
  • That's the expression problem: products changing more often than families means the wrong design.
  • Creation chains keep families together without a factory class: JDBC connection to statement to result set; DB-API connection to cursor.
  • In DI apps, profiles select per-environment families; hand-written factories suit per-request/tenant choices.
  • In-memory test families need the same contract tests as the real ones.

Say it in an interview

  • "We choose the theme factory once at startup; screens only use the factory they're given."
  • "A new theme is one class. A new widget touches every factory, so I'd add it with a default."
  • "Per tenant, I resolve the provider family at the edge of the request and pass it down."
  • "In tests, an in-memory factory gives a matched repository, queue and clock."

Practice

This skill comes with 11 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Abstract Factory Pattern free

Build a Matching UI Theme (Abstract Factory)

MediumProCoding problemJava · Python

Implement Solution.factoryFor(theme) so it returns the right UIFactory for "DARK" or "LIGHT" - DarkUIFactory for "DARK", LightUIFactory for "LIGHT" - so the button and checkbox it produces always match.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Render a Dialog With One Consistent Widget Family

MediumProCoding problemJava · Python

The Dialog class (already written) builds its widgets through a UIFactory and never mentions a concrete platform. Your job is to supply the factories so every dialog is drawn with one consistent family of widgets.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Abstract Factory Pattern free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime