Abstract Factory โ Creational design pattern with UML diagrams, Java implementation, and real-world examples.
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.
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 mixingButton btn = createButton("windows"); // Windows buttonCheckbox 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
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).
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
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.
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 1javax.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 2java.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 3javax.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 factoryDocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
// 2. Factory creates a product from its familyDocumentBuilder builder = factory.newDocumentBuilder();
// 3. Builder creates more products โ all from the same familyDocument doc = builder.parse(newFile("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 familyConnection conn = DriverManager.getConnection(
"jdbc:postgresql://localhost/mydb", "user", "pass"
);
// All products come from the PostgreSQL family โ guaranteed compatibleStatement stmt = conn.createStatement(); // product 1PreparedStatement ps = conn.prepareStatement("..."); // product 2DatabaseMetaData 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.
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 backUIFactory winFactory = newWindowsFactory();
UIFactory macFactory = newMacFactory();
Button btn = winFactory.createButton(); // WindowsCheckbox chk = macFactory.createCheckbox(); // macOS โ broken!
✔ Correct — client receives one factory
// โ Single factory โ all products from one familyvoidbuildUI(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
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.