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?

Once you start building a cross-platform UI, buttons, checkboxes, and text fields all need platform-specific versions. If every creation point grows an if (os === 'windows') new WindowsButton() branch, then buttons branch one way, checkboxes branch another way, and the logic spreads across the screen layer. The moment Linux is added, those branches fan out through the codebase. The larger problem is mismatched combinations. Put a Windows button next to a macOS checkbox and both behavior and visual consistency start to drift. Nothing in the structure guarantees related objects always come from the same variant.

Why did this approach emerge?

At first, directly calling new for a button or dialog rarely looks dangerous. The pressure appears when a product starts supporting multiple platforms and themes at once. Creation logic spreads through UI code and business code, every new platform forces you to revisit all the branching points, and objects that are supposed to move as a family start getting mixed. Abstract Factory comes from that pressure. Swapping one object at a time is no longer enough; you need a way to swap an entire family of cooperating objects together and keep creation responsibility in one place. If Factory Method opens a single creation point, Abstract Factory groups consistency at the family level.

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.

Boundaries & Distinctions

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