Conceptly
← All Concepts
🏭

Abstract Factory

CreationalAn interface for consistently creating families of related objects

Abstract Factory is a creational pattern that lets you create families of related objects without specifying their concrete classes. Client code depends only on the factory interface, so which product family gets created is determined at runtime.

β–ΆArchitecture Diagram

πŸ” Structure

Dashed line animations indicate the flow direction of data or requests

Why do you need it?

Imagine building a UI toolkit. You have buttons, checkboxes, and text fields, and each needs a Windows version and a macOS version. Handling this with conditionals means `if (os === 'windows') new WindowsButton()` is repeated for every component. When Linux is added, every branch has to be found and updated. The more serious problem is consistency. If a Windows button accidentally appears next to a macOS checkbox, behavior breaks or rendering fails. The issue is that nothing in the code structure guarantees related objects always come from the same variant.

Why did this approach emerge?

As object-oriented programming spread, new-keyword-based object creation code proliferated. It was not a problem in small programs, but as projects grew and supported more platforms, creation logic mixing into business logic became a recurring pain point. When GoF (Gang of Four) documented Abstract Factory in 1994, the practical motivation was that failing to separate creation responsibility by product family caused the blast radius of changes to spread across the entire codebase whenever a new variant was added. Where Factory Method delegates the creation of individual objects, Abstract Factory gathers the creation of objects that must work together into a single place -- a broader-scope solution.

How does it work inside?

Abstract Factory pivots on two axes. One is product type (button, checkbox), and the other is product variant (Windows, macOS). First, the AbstractFactory interface declares methods like createButton() and createCheckbox(). Then a ConcreteFactory for each variant (WindowsFactory, MacFactory) implements that interface. WindowsFactory.createButton() returns a WindowsButton; MacFactory.createButton() returns a MacButton. The client works exclusively with the AbstractFactory type. Depending on which ConcreteFactory is injected, the entire set of created objects changes, yet the client code needs no modification. This structure means adding a new variant (Linux) requires only a LinuxFactory and the corresponding Linux product classes.

In code

Factory interface and concrete factories

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

class WindowsFactory implements GUIFactory {
  createButton() { return new WindowsButton(); }
  createCheckbox() { return new WindowsCheckbox(); }
}

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

A single GUIFactory interface defines the creation of the entire product family. When the client receives a WindowsFactory, only Windows objects are produced; when it receives a MacFactory, only Mac objects come out.

Client code

function renderUI(factory: GUIFactory) {
  const button = factory.createButton();
  const checkbox = factory.createCheckbox();
  button.render();
  checkbox.render();
}

// Swapping the factory at runtime replaces the entire product family
const factory = os === 'windows'
  ? new WindowsFactory()
  : new MacFactory();
renderUI(factory);

The renderUI function knows nothing about concrete classes. Branching exists only at the single point where the factory is selected.

What is it often confused with?

Abstract Factory and Factory Method both encapsulate object creation, but they differ in scope. Factory Method is a pattern where one method delegates the creation of one object to a subclass, while Abstract Factory is a pattern that groups the creation of multiple related objects into a product family. The decision criterion is straightforward. If you need to create a single object whose implementation varies, Factory Method is sufficient. But if you have multiple objects that must be used together and must not be mixed -- like buttons and checkboxes -- Abstract Factory is needed. Abstract Factory has a limitation too. Adding a new product type (e.g., Slider) requires modifying all factory interfaces and their implementations. It is not well suited to situations where product types change frequently.

When should you use it?

Abstract Factory appears most often when the same application must work across multiple environments or configurations. Replacing OS-specific UI components in a cross-platform desktop app, or switching database-vendor-specific objects through a factory in a data access module, are representative examples. It is also useful for testing. In production you use a factory that creates real HTTP clients and DB connections; in tests you swap in a factory that creates mock objects, changing all dependencies without touching client code. The signal for adopting this pattern is 'conditional code that creates related objects as a group is repeated in multiple places, and the blast radius widens every time a new variant is added.' Conversely, when product types themselves change frequently or the combination constraints between objects are weak, the benefits of this pattern diminish.

Cross-platform UI -- creating matched sets of buttons, checkboxes, and scrollbars for Windows, macOS, and LinuxDatabase integration -- switching Connection, Command, and Reader objects for MySQL, PostgreSQL, or SQLite through a single factoryTheme system -- swapping color, icon, and font objects as a consistent set between dark and light modesTest environment -- replacing the entire production object family with a mock object family by switching one factory