Abstract Factory Pattern
Abstract Factory Pattern
Provide an interface for creating families of related or dependent objects without specifying their concrete classes.
Intent
The AbstractFactory interface declares creation methods for each distinct product type in the family. ConcreteFactories implement the interface, producing a coordinated set of ConcreteProducts. The Client works through the AbstractFactory and AbstractProduct interfaces — swapping one ConcreteFactory swaps the entire product family atomically. This guarantees that products from one family are always used together, eliminating cross-family mismatches (e.g., a Windows button with a Mac checkbox).
When NOT to Use
- Only one product type needs to be created — use Factory Method instead
- The product family is fixed and never changes — the factory interface adds indirection for no benefit
- New product types must be added frequently — each new type requires changing every ConcreteFactory (the "open for extension" cost is high)
- Products are simple value objects — a constructor is clearer
When to Use
- System must be independent of how its products are created and composed
- System is configured with one of multiple families (e.g., UI themes, database drivers, platform-specific widgets)
- Products within a family must be used together — the factory enforces consistency (no mixing WinButton with MacCheckbox)
How It Works
Participants: AbstractFactory (declares createA(), createB()...), ConcreteFactory (implements all create methods for one family), AbstractProduct (interface per product type), ConcreteProduct (per family per type), Client (uses only abstract interfaces).
Swapping the factory object at runtime switches the entire product family. The client receives a factory at construction time (dependency injection) and never calls new directly on concrete products.
Class Diagram
classDiagram
class AbstractFactory {
<<interface>>
+createProductA()* ProductA
+createProductB()* ProductB
}
class ConcreteFactory1 {
+createProductA() ProductA
+createProductB() ProductB
}
class ConcreteFactory2 {
+createProductA() ProductA
+createProductB() ProductB
}
class ProductA {
<<interface>>
}
class ProductB {
<<interface>>
}
class ConcreteProductA1
class ConcreteProductA2
class ConcreteProductB1
class ConcreteProductB2
AbstractFactory <|.. ConcreteFactory1
AbstractFactory <|.. ConcreteFactory2
ProductA <|.. ConcreteProductA1
ProductA <|.. ConcreteProductA2
ProductB <|.. ConcreteProductB1
ProductB <|.. ConcreteProductB2
ConcreteFactory1 ..> ConcreteProductA1 : creates
ConcreteFactory1 ..> ConcreteProductB1 : creates
ConcreteFactory2 ..> ConcreteProductA2 : creates
ConcreteFactory2 ..> ConcreteProductB2 : creates
Client --> AbstractFactory
TypeScript Example
// Abstract Factory — TypeScript
interface Button { render(): void; }
interface Checkbox { render(): void; }
interface GUIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class WinButton implements Button {
render() { console.log("Windows button"); }
}
class WinCheckbox implements Checkbox {
render() { console.log("Windows checkbox"); }
}
class WinFactory implements GUIFactory {
createButton(): Button { return new WinButton(); }
createCheckbox(): Checkbox { return new WinCheckbox(); }
}
// Client works only through abstract interfaces
function renderUI(factory: GUIFactory) {
factory.createButton().render();
factory.createCheckbox().render();
}
renderUI(new WinFactory());Java Example
// Abstract Factory — Java
interface Button { void render(); }
interface Checkbox { void render(); }
interface GUIFactory {
Button createButton();
Checkbox createCheckbox();
}
class WinButton implements Button {
@Override public void render() { System.out.println("Windows button"); }
}
class WinCheckbox implements Checkbox {
@Override public void render() { System.out.println("Windows checkbox"); }
}
class WinFactory implements GUIFactory {
@Override public Button createButton() { return new WinButton(); }
@Override public Checkbox createCheckbox() { return new WinCheckbox(); }
}Confusion With
| Pattern | Key Difference |
|---|---|
| Factory-Method-Pattern | Factory Method creates one product type via subclass override; Abstract Factory creates a coordinated family of products via a factory object with multiple creation methods |
| Static factory methods | Collections.unmodifiableList() — a static utility; not a GoF pattern, no family concept, no interface |
| Service Locator | Service Locator retrieves existing instances; Abstract Factory creates new product instances |
Related Concepts
| Concept | Relationship |
|---|---|
| Factory-Method-Pattern | Abstract Factory typically uses Factory Methods internally for each product type |
| Builder-Pattern | Builder constructs one complex object step-by-step; Abstract Factory creates families in one call |
| Singleton-Pattern | ConcreteFactory objects are often Singletons (prefer DI-managed single instance) |
| Prototype-Pattern | Factories can use Prototype to clone products rather than construct them |
Sources
- Gamma et al., Design Patterns, 1994, pp. 87–95 — authoritative definition and participants
- refactoring.guru/design-patterns/abstract-factory — modern TypeScript framing