Creational Kit

Abstract Factory

Abstract Factory groups the creation of several related objects behind one interface, so the objects a program builds always come from the same matching set.

Complexity
Popularity

Problem

A UI library needs to render buttons, checkboxes, and text fields that look native on Windows, macOS, and Linux. Each platform has its own widget classes, and a screen only looks right if every widget on it comes from the same platform's set - mixing a Windows-style button with a macOS-style checkbox breaks the illusion immediately.

If the screen-building code instantiates WindowsButton, MacCheckbox, and so on directly, two things go wrong. First, the code that assembles a screen is littered with if (platform === 'mac') branches wherever a widget is created. Second, nothing stops a careless call from grabbing a widget from the wrong platform's set - the compiler has no concept of "these classes belong together."

Solution

Give every product type in the family its own interface (Button, Checkbox) and write one implementation class per platform per product. Then introduce a factory interface with one creation method per product type - createButton(), createCheckbox() - and implement it once per platform: WindowsFactory, MacFactory, LinuxFactory. Each concrete factory only ever knows how to build its own platform's widgets, so it physically cannot hand out a mismatched pair.

The screen-assembly code receives a factory instance (chosen once, e.g., at startup, based on the detected OS) and calls its creation methods without ever naming a concrete widget class. Switching platforms means swapping which factory gets injected - nothing else in the code changes.

When to Use

  • Reach for Abstract Factory when a system must stay agnostic to which concrete family of products it works with, and that family is chosen at runtime or configuration time.
  • It fits well when several related product types must always be used together as a matching set, and accidentally mixing variants would be a real bug.
  • Consider it when you already have a Factory Method for one product and realize a second, third, and fourth related product need the same variant-based creation logic.

Real-World Examples

  • Java AWT/Swing UIManager - swapping the look-and-feel (Metal, Nimbus, or a platform-native one) swaps out an entire factory that produces matching buttons, scrollbars, and menus.
  • document.createElement behind DOM implementations - different rendering engines (jsdom vs. a real browser) act as interchangeable factories producing element objects that all satisfy the same DOM interfaces.
  • Database driver packages in ORMs (e.g., TypeORM, Sequelize) - selecting postgres vs. mysql in the config swaps in a whole family of dialect-specific connection, query, and transaction objects.