Provide an interface for creating families of related objects without specifying their concrete classes — ensuring products from the same family are always used together.
The Abstract Factory pattern is a creational design pattern that lets you create families of related objects through a single interface — without specifying the concrete classes of the objects you're creating.
Think of it as a furniture showroom: you pick a style (Modern, Victorian, Art Deco). Each style gives you a matching sofa, chair, and table. You'd never mix a Victorian sofa with a Modern chair — the factory ensures every product belongs to the same family.
Key Idea: Create families of related objects through one interface. Swap the entire family by swapping the factory.
| Aspect | Abstract Factory | Factory Method |
|---|---|---|
| Creates | A family of related objects | One type of object |
| Consistency | Products guaranteed compatible | No such guarantee |
| Mechanism | Composition | Inheritance |
Declares creation methods for each distinct product type in the family.
Implements the abstract factory interface for a specific product family.
Interface for each distinct type of product (Button, Checkbox, etc).
The real objects created by a concrete factory.
// Without Abstract Factory — risky mismatch Button btn = new WindowsButton(); Checkbox cb = new MacCheckbox(); // OOPS! Mixed families.
// Factory guarantees consistency UIComponentFactory factory = new WindowsUIFactory(); Button btn = factory.createButton(); // Guaranteed Windows
// Abstract Factory Pattern — Cross-Platform UI Components
// ─── Abstract Products ────────────────────────────────────────
interface Button {
void render();
void onClick();
}
interface Checkbox {
void render();
void toggle();
}
interface TextInput {
void render();
String getValue();
}
// ─── Concrete Products: Windows ───────────────────────────────
class WindowsButton implements Button {
public void render() { System.out.println("[Windows] Rendering flat button with accent color"); }
public void onClick() { System.out.println("[Windows] Button click — ripple effect"); }
}
class WindowsCheckbox implements Checkbox {
public void render() { System.out.println("[Windows] Rendering square checkbox"); }
public void toggle() { System.out.println("[Windows] Checkbox toggled — checkmark animates"); }
}
class WindowsTextInput implements TextInput {
public void render() { System.out.println("[Windows] Rendering underline text field"); }
public String getValue() { return "Windows input value"; }
}
// ─── Concrete Products: macOS ─────────────────────────────────
class MacButton implements Button {
public void render() { System.out.println("[macOS] Rendering pill-shaped button"); }
public void onClick() { System.out.println("[macOS] Button click — subtle shadow"); }
}
class MacCheckbox implements Checkbox {
public void render() { System.out.println("[macOS] Rendering rounded checkbox"); }
public void toggle() { System.out.println("[macOS] Checkbox toggled — smooth slide"); }
}
class MacTextInput implements TextInput {
public void render() { System.out.println("[macOS] Rendering rounded bordered field"); }
public String getValue() { return "macOS input value"; }
}
// ─── Abstract Factory ─────────────────────────────────────────
interface UIComponentFactory {
Button createButton();
Checkbox createCheckbox();
TextInput createTextInput();
}
// ─── Concrete Factories ───────────────────────────────────────
class WindowsUIFactory implements UIComponentFactory {
public Button createButton() { return new WindowsButton(); }
public Checkbox createCheckbox() { return new WindowsCheckbox(); }
public TextInput createTextInput() { return new WindowsTextInput(); }
}
class MacUIFactory implements UIComponentFactory {
public Button createButton() { return new MacButton(); }
public Checkbox createCheckbox() { return new MacCheckbox(); }
public TextInput createTextInput() { return new MacTextInput(); }
}
// ─── Client — uses factory without knowing concrete types ──────
class LoginForm {
private Button submitBtn;
private Checkbox rememberMe;
private TextInput emailInput;
public LoginForm(UIComponentFactory factory) {
submitBtn = factory.createButton();
rememberMe = factory.createCheckbox();
emailInput = factory.createTextInput();
}
public void render() {
System.out.println("\n--- Rendering Login Form ---");
emailInput.render();
rememberMe.render();
submitBtn.render();
}
public void submit() {
submitBtn.onClick();
System.out.println("Email: " + emailInput.getValue());
}
}
// ─── Entry point ──────────────────────────────────────────────
public class App {
public static void main(String[] args) {
String os = System.getProperty("os.name").toLowerCase();
UIComponentFactory factory = os.contains("mac")
? new MacUIFactory()
: new WindowsUIFactory();
LoginForm form = new LoginForm(factory);
form.render();
form.submit();
// All components are guaranteed to match the same platform!
}
}When your app must run on multiple platforms and each needs its own matching look-and-feel.
WindowsUIFactory, MacUIFactoryWhen switching environments should swap the entire family (DB, Cache, Queue) together.
LocalDevFactory, AWSFactoryWhen the entire UI must switch coherently between themes.
LightThemeFactory, DarkThemeFactoryCalling UIManager.setLookAndFeel() swaps the factory — all components re-render in the new style.
Creates platform-specific query builders matched to the connected database vendor.
Platform-specific rendering produces iOS UIKit views or Android View objects depending on the factory.