Abstract Factory Pattern
Provides an interface for creating families of related or dependent objects without specifying their concrete classes. Abstract Factory is a super-factory that creates other factories, allowing you to produce objects that belong together without coupling your code to their concrete implementations.
✦ Problem
When your application must work with multiple families of related products (e.g., UI components for different operating systems), creating objects directly would scatter platform-specific code throughout your application. Adding a new product family or a new product type requires changing many places, creating fragile and unmaintainable code.
✦ Solution
Declare interfaces for each distinct product in the product family, then create an abstract factory interface with creation methods for all products. For each variant of a product family, create a separate factory class that returns products of a particular kind. The client code works with factories and products only through their abstract interfaces.
Participants
| Role | Responsibility |
|---|---|
| AbstractFactory | Declares an interface for operations that create abstract product objects |
| ConcreteFactory | Implements the operations to create concrete product objects for a specific family |
| AbstractProduct | Declares an interface for a type of product object |
| ConcreteProduct | Defines a product object created by the corresponding concrete factory |
| Client | Uses only interfaces declared by AbstractFactory and AbstractProduct classes |
TypeScript Example
interface Button {
render(): string;
}
interface Checkbox {
check(): string;
}
interface UIFactory {
createButton(): Button;
createCheckbox(): Checkbox;
}
class DarkButton implements Button {
render() { return "<button class='dark'>Click</button>"; }
}
class DarkCheckbox implements Checkbox {
check() { return "<input type='checkbox' class='dark'/>"; }
}
class LightButton implements Button {
render() { return "<button class='light'>Click</button>"; }
}
class LightCheckbox implements Checkbox {
check() { return "<input type='checkbox' class='light'/>"; }
}
class DarkThemeFactory implements UIFactory {
createButton() { return new DarkButton(); }
createCheckbox() { return new DarkCheckbox(); }
}
class LightThemeFactory implements UIFactory {
createButton() { return new LightButton(); }
createCheckbox() { return new LightCheckbox(); }
}
function buildUI(factory: UIFactory) {
const btn = factory.createButton();
const cb = factory.createCheckbox();
return `${btn.render()} ${cb.check()}`;
}
console.log(buildUI(new DarkThemeFactory()));Real-World Example
Cross-platform UI toolkits like Qt or Java Swing use Abstract Factory. A toolkit defines an abstract factory for creating widgets (buttons, menus, scrollbars). Each supported platform provides a concrete factory that produces native-looking widgets. The application code only uses abstract widget interfaces, so switching from Windows to macOS requires only swapping the factory, not changing any application logic.
✓ When to Use
- •Your system must be independent of how its products are created and composed
- •You need to enforce that related products are used together
- •You want to provide a library of products revealing only their interfaces, not implementations
- •You need to support multiple product families and want to switch between them easily
✗ When Not to Use
- •You only have one product family and don't expect to add more
- •Product families don't share common interfaces
- •Adding the pattern to an existing system requires significant refactoring with little benefit
Understanding the Abstract Factory Pattern
The Abstract Factory pattern is one of the most important creational design patterns in object-oriented software design. Originally cataloged by the Gang of Four (Erich Gamma, Richard Helm, Ralph Johnson, and John Vlissides) in their seminal 1994 book "Design Patterns: Elements of Reusable Object-Oriented Software," this pattern continues to be a cornerstone of modern software architecture.
Provides an interface for creating families of related or dependent objects without specifying their concrete classes. Abstract Factory is a super-factory that creates other factories, allowing you to produce objects that belong together without coupling your code to their concrete implementations. The pattern involves the following key participants: AbstractFactory, ConcreteFactory, AbstractProduct, ConcreteProduct, Client. Each participant has a well-defined role, and the interactions between them create a flexible, maintainable structure that can evolve with changing requirements.
In TypeScript and modern JavaScript development, the Abstract Factory pattern is particularly valuable because the language's type system and interface support allow you to express the pattern with compile-time safety. TypeScript generics can make Abstract Factory implementations even more flexible and reusable while maintaining strong type checking throughout the pattern's structure.
Knowing when to apply the Abstract Factory pattern is as important as knowing how. Common use cases include: Your system must be independent of how its products are created and composed; You need to enforce that related products are used together; You want to provide a library of products revealing only their interfaces, not implementations. However, overusing design patterns can lead to unnecessarily complex code. Always evaluate whether the pattern genuinely solves your problem or if a simpler approach would suffice.
The Abstract Factory pattern is related to several other design patterns: Factory Method, Builder, Prototype, Singleton. Understanding these relationships helps you choose the right pattern for your specific situation and combine patterns effectively when building complex systems.
Related Patterns
Defines an interface for creating an object, but lets subclasses decide which class to instantiate. Factory Method lets …
Separates the construction of a complex object from its representation, allowing the same construction process to create…
Creates new objects by copying an existing object, known as the prototype. This pattern is useful when creating an insta…
Ensures a class has only one instance and provides a global point of access to it. The Singleton pattern restricts insta…
More Creational Patterns
Explore All Design Patterns
Browse our complete reference of 23 design patterns with TypeScript examples, UML participants, and practical guidance.