Creational

Abstract Factory Pattern

Create families of related objects without specifying concrete classes. An intermediate creational pattern — the foundation of every cross-platform toolkit, themed UI system, and pluggable architecture.

Overview ยท Creational ยท Singleton ยท Factory Method ยท Abstract Factory ยท Builder ยท Prototype ยท Adapter ยท Bridge ยท Composite ยท Decorator ยท Facade ยท Flyweight ยท Proxy ยท Observer ยท Strategy ยท Command ยท Template Method ยท Chain of Resp. ยท State ยท Mediator ยท Iterator ยท Visitor ยท Memento ยท Interpreter
Category: Creational Difficulty: Intermediate Interview: Tier 2 Confused with: Factory Method
01
Section One ยท The Problem

Why Abstract Factory Exists

You are building a cross-platform UI toolkit. Your app needs to render buttons, checkboxes, and text fields — but each must look native on Windows, macOS, and the Web. You start with Factory Method: one factory for buttons, another for checkboxes, another for text fields. That works until someone creates a Windows button next to a macOS checkbox. The products are related — they must come from the same family — but nothing in your code enforces that constraint. Every widget factory is independent, so mixing families is a silent, invisible bug.

Naive approach — separate factories with no family enforcement
// โœ— Three independent factory methods โ€” nothing prevents mixing Button btn = createButton("windows"); // Windows button Checkbox chk = createCheckbox("macos"); // macOS checkbox โ† wrong family! TextField txt = createTextField("web"); // Web text field โ† wrong family! // The UI looks broken โ€” Windows button + macOS checkbox + Web input // No compile error, no runtime error โ€” just visual chaos

What goes wrong:

  • No family consistency — each factory method is independent; nothing guarantees all widgets come from the same platform
  • String-based selection — passing "windows" / "macos" as strings is error-prone and scattered across the codebase
  • Combinatorial explosion — 3 product types × 3 platforms = 9 if/else branches across 3 separate factory methods, each needing to stay in sync
  • Violation of implicit contract — the products are designed to work together, but the code makes that relationship invisible
Without Abstract Factory — independent factories allow family mixing
Application createButton("win") createCheckbox("mac") createTextField("web") ✗ Three independent factories — nothing prevents mixing Windows + macOS + Web ✗ Products designed as a family, but code treats them as unrelated

This is the problem Abstract Factory solves — group related factory methods into a single interface so that the client gets an entire family of compatible products from one factory, making it impossible to mix Windows buttons with macOS checkboxes.

02
Section Two ยท The Pattern

What Is Abstract Factory?

Abstract Factory is a creational pattern that provides an interface for creating families of related objects without specifying their concrete classes. Instead of calling individual factory methods for each product, the client receives a single factory object that produces all the products for one variant. Every product from that factory is guaranteed to be compatible — you get a Windows button and a Windows checkbox and a Windows text field, never a mix.

GoF Intent: “Provide an interface for creating families of related or dependent objects without specifying their concrete classes.”
— Gamma, Helm, Johnson, Vlissides (1994)
Analogy — a furniture showroom: Imagine you walk into IKEA and say “I want a Modern living room set.” The showroom (the Abstract Factory) gives you a Modern sofa, a Modern coffee table, and a Modern bookshelf — all from the same style family. If you ask for Victorian, you get a Victorian sofa, Victorian coffee table, Victorian bookshelf. You never pick a Modern sofa and a Victorian table — the showroom guarantees family consistency. Each style is a Concrete Factory, each piece of furniture is a Product, and the showroom’s catalogue is the Abstract Factory interface listing what every style must provide.

Key insight: Abstract Factory is Factory Method applied at the family level. Factory Method creates one product via one overridable method. Abstract Factory bundles multiple factory methods into a single interface, guaranteeing that all products returned by one concrete factory belong to the same family. This is what separates it from Factory Method (single product) and from Builder (step-by-step construction of one complex object).

Abstract Factory declares createButton(), createCheckbox(), createTextField()
Client depends only on the factory interface — never on any concrete product or factory class
Each Concrete Factory (WindowsFactory, MacFactory) implements all create methods
Every product from one factory belongs to the same family — mixing is structurally impossible
Client receives the factory via constructor or config — one line decides the entire family
Switching from Windows to macOS = swapping one factory object, zero code changes in the client
Adding a new family (e.g. Linux) = one new concrete factory class
Open/Closed Principle: existing factories and client code remain untouched
03
Section Three ยท Anatomy

Participants & Structure

Participant Role In the Analogy
Abstract Factory An interface that declares a create method for each product type in the family (createButton(), createCheckbox()). The client programs against this type only. The showroom catalogue — lists every piece of furniture a style must include.
Concrete Factory Implements the abstract factory to produce all products for one specific family. Each concrete factory guarantees family consistency. The “Modern” section or the “Victorian” section — each supplies a matching set.
Abstract Product An interface for one type of product (e.g. Button, Checkbox). Each product type has its own abstract product interface. The concept of “a sofa” or “a coffee table” regardless of style.
Concrete Product A specific implementation of an abstract product for one family (e.g. WindowsButton, MacButton). Created only by its matching concrete factory. A Modern sofa, a Victorian sofa — same role, different style.
Client Uses the abstract factory and abstract product interfaces only. It receives a factory via constructor or configuration and never references any concrete class. The customer — asks for “a living room set” without naming a specific manufacturer.
Abstract Factory — UML Class Diagram
«interface» UIFactory + createButton() : Button + createCheckbox() : Checkbox «interface» Button + render() : void «interface» Checkbox + toggle() : void «creates» Windows WindowsFactory + createButton() WinButton + render() WinCheckbox + toggle() creates » macOS MacFactory + createButton() MacButton + render() MacCheckbox + toggle() creates » Application uses only interfaces ■ Blue = abstract / interface ■ Green = concrete class ■ Dark = client - - ▶ gold = creates ▷ dashed = implements □ dashed outline = product family --▷ to interface = dependency
Five participants, two dimensions:
  • Abstract Factory has a grid structure — factories on one axis, product types on the other.
  • Each row is a family (Windows, macOS); each column is a product type (Button, Checkbox).
  • The client holds a reference to one row (one factory) and gets all columns (all product types) from it.
  • This is what makes family mixing structurally impossible.
04
Section Four ยท How It Works

The Pattern In Motion

Scenario: A cross-platform application that renders UI differently on Windows and macOS. The application receives a factory at startup and uses it to create all widgets — never naming a concrete class.

Step 1 — Bootstrap picks the factory: factory = new MacFactory()
This single line decides the entire product family. The rest of the application is factory-agnostic — it only sees UIFactory.
Step 2 — App calls factory.createButton()
MacFactory.createButton() returns a MacButton. The app stores it as Button (the interface). It has no idea it’s a Mac button.
Step 3 — App calls factory.createCheckbox()
MacFactory.createCheckbox() returns a MacCheckbox. Both the button and checkbox are guaranteed to be from the same family — the factory enforces this.
Step 4 — App calls button.render() and checkbox.toggle()
Each product behaves according to its platform. Swapping to Windows means changing one line at bootstrap (new WindowsFactory()) — zero edits anywhere else in the app.
Step 5 — Product team requests Linux support
Create LinuxFactory, LinuxButton, LinuxCheckbox. Existing factories, products, and client code remain untouched — Open/Closed Principle.
Before / After — independent factories vs. Abstract Factory
BEFORE — independent factories App WinButton MacCheckbox WebTextField ✗ mixed families! AFTER — Abstract Factory App UIFactory interface Button Checkbox WinF MacF creates ✔ Client depends only on interfaces ✔ One factory = one consistent family ✔ New platform = new factory, zero edits RUNTIME FLOW — macOS selected Bootstrap new MacFactory() family chosen here createButton() MacButton render() createCheckbox() MacCheckbox toggle()
The pattern in pseudocode
// โ”€โ”€ Abstract Factory โ”€โ”€ interface UIFactory { Button createButton(); Checkbox createCheckbox(); } // โ”€โ”€ Concrete Factory: macOS โ”€โ”€ class MacFactory implements UIFactory { Button createButton() { return new MacButton(); } Checkbox createCheckbox() { return new MacCheckbox(); } } // โ”€โ”€ Client code โ”€โ”€ void buildUI(UIFactory factory) { Button btn = factory.createButton(); // MacButton (unknown to client) Checkbox chk = factory.createCheckbox(); // MacCheckbox (same family) btn.render(); chk.toggle(); }
Abstract Factory vs. Factory Method:
  • Notice how UIFactory bundles multiple factory methods into one interface.
  • Factory Method has one abstract creation method; Abstract Factory has several, each for a different product type.
  • The client calls one factory and gets an entire coordinated family.
  • That’s the fundamental difference — single product vs. product family.
05
Section Five ยท Java Stdlib

You Already Use This

Abstract Factory is deeply embedded in the JDK — especially in XML processing and JDBC. Anywhere you see a factory class that produces a family of related objects (parser + builder + transformer, or connection + statement + resultset), that’s Abstract Factory at work.

IN JAVA
Example 1 javax.xml.parsers.DocumentBuilderFactory — this is a textbook Abstract Factory. Calling DocumentBuilderFactory.newInstance() returns a platform-specific factory (Xerces, SAX, etc.). That factory then creates a DocumentBuilder, which in turn produces Document, Element, and Node objects — all from the same XML implementation family. You never reference a concrete XML parser class.
Example 2 java.sql.DriverManager / java.sql.Connection — when you call DriverManager.getConnection(url), the JDBC driver acts as an Abstract Factory. The returned Connection produces a family of related objects: Statement, PreparedStatement, CallableStatement, DatabaseMetaData. All come from the same driver family (MySQL, PostgreSQL, Oracle) and are guaranteed to be compatible. You code against the java.sql interfaces only.
Example 3 javax.xml.transform.TransformerFactory — another XML Abstract Factory. TransformerFactory.newInstance() returns a vendor-specific factory that creates Transformer and Templates objects. Swap the system property javax.xml.transform.TransformerFactory and you get a completely different implementation family — zero code changes.
Stdlib usage — DocumentBuilderFactory as Abstract Factory
// 1. Get the Abstract Factory โ€” platform picks the concrete factory DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); // 2. Factory creates a product from its family DocumentBuilder builder = factory.newDocumentBuilder(); // 3. Builder creates more products โ€” all from the same family Document doc = builder.parse(new File("config.xml")); Element root = doc.getDocumentElement(); // You never wrote: new XercesDocumentBuilder() // You never wrote: new XercesDocument() // The factory guarantees all objects are compatible System.out.println(root.getTagName()); // works regardless of XML impl
Stdlib usage — JDBC Connection as Abstract Factory
// Connection acts as an Abstract Factory for the JDBC product family Connection conn = DriverManager.getConnection( "jdbc:postgresql://localhost/mydb", "user", "pass" ); // All products come from the PostgreSQL family โ€” guaranteed compatible Statement stmt = conn.createStatement(); // product 1 PreparedStatement ps = conn.prepareStatement("..."); // product 2 DatabaseMetaData meta = conn.getMetaData(); // product 3 // Switch to MySQL? Change the URL string โ€” zero code changes below
Factory vs. Abstract Factory in the JDK:
  • Calendar.getInstance() is Factory Method — it returns one product (a Calendar).
  • DocumentBuilderFactory.newInstance() is Abstract Factory — the factory it returns can produce a family of related products (DocumentBuilder, Document, Element, Node).
  • The distinction is always: one product vs. product family.
06
Section Six ยท Implementation

Build It Once

Domain: Cross-Platform UI Toolkit (Windows, macOS). Each factory produces a coordinated family of widgets — Button and Checkbox. The client application works entirely through interfaces and never references a concrete widget class.

Java — Abstract Factory UI Toolkit (core)
// โ”€โ”€ Abstract Products โ”€โ”€ interface Button { void render(); String getStyle(); } interface Checkbox { void toggle(); String getStyle(); } // โ”€โ”€ Abstract Factory โ”€โ”€ interface UIFactory { Button createButton(); Checkbox createCheckbox(); } // โ”€โ”€ Windows Family โ”€โ”€ class WindowsButton implements Button { public void render() { System.out.println(" [Win Button] Rendering flat Windows-style button"); } public String getStyle() { return "Windows"; } } class WindowsCheckbox implements Checkbox { public void toggle() { System.out.println(" [Win Checkbox] Toggling square Windows checkbox"); } public String getStyle() { return "Windows"; } } class WindowsFactory implements UIFactory { public Button createButton() { return new WindowsButton(); } public Checkbox createCheckbox() { return new WindowsCheckbox(); } } // โ”€โ”€ macOS Family โ”€โ”€ class MacButton implements Button { public void render() { System.out.println(" [Mac Button] Rendering rounded aqua-style button"); } public String getStyle() { return "macOS"; } } class MacCheckbox implements Checkbox { public void toggle() { System.out.println(" [Mac Checkbox] Toggling rounded macOS checkbox"); } public String getStyle() { return "macOS"; } } class MacFactory implements UIFactory { public Button createButton() { return new MacButton(); } public Checkbox createCheckbox() { return new MacCheckbox(); } }
Extending the system:
  • To add a Web theme, create WebButton implements Button, WebCheckbox implements Checkbox, and WebFactory implements UIFactory.
  • Three new classes, zero edits to existing code.
  • The Application class works unchanged because it only depends on UIFactory, Button, and Checkbox interfaces.
07
Section Seven ยท Watch Out

Common Mistakes

Mistake #1 — Letting the client pick products from different factories: The entire point of Abstract Factory is family consistency. If your client receives two factories and calls factoryA.createButton() and factoryB.createCheckbox(), you’ve defeated the pattern. The client must receive one factory and use it for all products.
✗ Wrong — client mixes factories
// โœ— Two factories in the same scope โ€” family mixing is back UIFactory winFactory = new WindowsFactory(); UIFactory macFactory = new MacFactory(); Button btn = winFactory.createButton(); // Windows Checkbox chk = macFactory.createCheckbox(); // macOS โ† broken!
✔ Correct — client receives one factory
// โœ“ Single factory โ€” all products from one family void buildUI(UIFactory factory) { Button btn = factory.createButton(); Checkbox chk = factory.createCheckbox(); // Both guaranteed to be from the same family }
Mistake #2 — Adding a new product type to the interface after release:
  • If you add createTextField() to UIFactory after shipping, every existing concrete factory breaks — they all need a new method.
  • This is the biggest tradeoff of Abstract Factory: adding new product types is expensive (every factory must be updated), while adding new product families is cheap (just one new factory class).
  • Know the difference before choosing this pattern.
Mistake #3 — Confusing Abstract Factory with Factory Method:
  • Factory Method — one abstract method, one product, inheritance-based. The subclass decides which single product to create.
  • Abstract Factory — an interface with multiple factory methods, producing a family of products. The factory object is composed into the client, not inherited.
If your factory has only one create method and no related products, you probably want Factory Method, not Abstract Factory.
Mistake #4 — Making the factory a Singleton:
  • It’s tempting to make each concrete factory a Singleton since you typically need only one.
  • But Singletons make testing painful — you can’t inject a mock factory for unit tests.
  • Instead, pass the factory as a constructor parameter (dependency injection).
  • This keeps the client testable and the factory swappable.
08
Section Eight ยท Decision Guide

When To Use Abstract Factory

Use Abstract Factory When
  • Your system must work with families of related products that must be used together — mixing products from different families would be a bug
  • You want to enforce family consistency at the structural level — the compiler (not developer discipline) prevents mixing
  • You need to support multiple platforms, themes, or vendors and want to swap an entire product suite with a single configuration change
  • You want your client code to depend on product interfaces only — no concrete product class should appear outside the factory
  • You anticipate adding new families (e.g. a new platform) frequently — each new family is just one new factory class
Avoid Abstract Factory When
  • You only create one product type — Factory Method is simpler and sufficient
  • You expect to add new product types frequently — every new product forces changes to every existing factory (the pattern’s Achilles’ heel)
  • The products are not related — if a Button and a Logger have no family relationship, bundling them in one factory is artificial complexity
  • Dependency injection or a service locator already handles your creation needs without the ceremony of factory hierarchies
Abstract Factory vs. Confused Patterns
Pattern Creates Mechanism When to pick it
Abstract Factory ← this Family of related products Interface with multiple factory methods Products must be used together (e.g. themed UI widgets)
Factory Method One product type Abstract method overridden in subclass Subclass decides which single product to create
Builder One complex product Step-by-step construction with director Product has many parts or optional configuration
Prototype Cloned copies of existing objects Clone method on the product itself Creating from scratch is expensive; cloning is cheaper
Decision Flowchart
Need to create objects without naming concrete classes? No Use new directly Yes Multiple related products as a family? No Subclass decides? Yes Factory Method No Static Factory or Builder Yes Must enforce family consistency? No Separate Factory Methods (one per product type) Yes Abstract Factory One factory → entire coordinated family
09
Section Nine ยท Practice

Problems To Solve

Abstract Factory problems test whether you can identify product families, enforce consistency across them, and extend the system without modifying existing code.

Difficulty Problem Key Insight
Easy Theme-Based UI Kit
Build a UI system that supports “Dark” and “Light” themes. Each theme produces a Panel (with a background colour) and a Label (with a text colour). The client renders a screen using one theme — mixing dark panels with light labels is not allowed.
Define UIThemeFactory with createPanel() and createLabel(). DarkThemeFactory returns dark-themed products; LightThemeFactory returns light-themed products. The client receives one factory and calls both methods. Family consistency is structural.
Medium Cross-Platform File Dialog
Design a file dialog system that works on Windows, macOS, and Linux. Each platform provides a different FileChooser, ProgressBar, and ConfirmDialog. The application must never mix platform-specific components.
DialogFactory interface with three create methods. Each platform has a concrete factory. The tricky part: adding a fourth product (Tooltip) requires editing the interface and all three factories — this is the pattern’s tradeoff. Discuss how default methods in Java 8+ can mitigate this.
Medium Database Access Layer
A data access layer must support MySQL and PostgreSQL. Each database requires a compatible set of Connection, Command, and ResultSet objects. Using a MySQL connection with a PostgreSQL command object would corrupt data.
DatabaseFactory interface producing three product types. MySQLFactory and PostgresFactory each return their own family. The client code (a repository layer) depends only on the abstract products. Switching databases is a config change, not a code change.
Hard Document Export Pipeline
Design an export system that produces coordinated document parts: Header, Body, Footer, and StyleSheet. Supported formats: PDF, HTML, and Markdown. Each format has its own rendering rules. Adding a new format (e.g. DOCX) must not require changes to existing format factories or the pipeline client.
DocumentFactory with four factory methods. Each format is a concrete factory. The pipeline calls all four methods and assembles the parts. The hard part: each product might need to reference other products in the same family (e.g. Body applies the StyleSheet). Solve with a two-pass assembly: create all products, then link them. Also consider using Abstract Factory + Builder together — the factory selects the builder family.
Interview Tip:
  • When asked about Abstract Factory, the interviewer wants to see: (1) a factory interface with multiple create methods, not just one; (2) at least two concrete factories producing different families; (3) a client that receives the factory via injection and never names a concrete product; (4) a clear explanation of the tradeoff — adding new families is easy (one new factory), but adding new product types is expensive (every factory changes).
  • If you can contrast this with Factory Method (single product, inheritance-based), you’ve nailed it.