Low-level design3 min
Abstract Factory
Type: Creational Pattern
Relevance: Medium/High. Commonly used in enterprise systems requiring families of related objects.
The Abstract Factory pattern lets you produce families of related objects without specifying their concrete classes. It is essentially a "Factory of Factories."
Real-Life Analogy
Think of a Furniture Store. A furniture store sells related families of items, such as Modern, Victorian, and ArtDeco.
A family consists of a Chair, a Sofa, and a CoffeeTable.
If a customer buys a Victorian Chair, they expect the Victorian Sofa to match it perfectly. You would use a VictorianFurnitureFactory to ensure all created products belong to the Victorian family and are compatible.
The Problem
If you use the standard Factory Method, you might accidentally mix a ModernChair with a VictorianSofa. The Abstract Factory guarantees that all products created by a specific factory variant are compatible with each other.
How to Implement Abstract Factory
- Explicitly declare interfaces for each distinct product in the product family (e.g.,
Chair,Sofa). - Create the Abstract Factory interface, which declares creation methods for all products in the family (
createChair(),createSofa()). - Create concrete factory classes that implement the Abstract Factory interface for a specific variant (e.g.,
ModernFurnitureFactory,VictorianFurnitureFactory).
Example in Code
// 1. Abstract Products
interface Chair { hasLegs(): boolean; sitOn(): void; }
interface Sofa { hasCushions(): boolean; lieOn(): void; }
// Concrete Products (Victorian Family)
class VictorianChair implements Chair {
hasLegs() { return true; }
sitOn() { console.log("Sitting on a fancy Victorian chair."); }
}
class VictorianSofa implements Sofa {
hasCushions() { return true; }
lieOn() { console.log("Lying on a velvet Victorian sofa."); }
}
// Concrete Products (Modern Family)
class ModernChair implements Chair {
hasLegs() { return false; } // It's a weird hover chair
sitOn() { console.log("Sitting on a sleek Modern chair."); }
}
class ModernSofa implements Sofa {
hasCushions() { return false; } // It's just a slab
lieOn() { console.log("Lying on a minimalist Modern sofa."); }
}
// 2. Abstract Factory
interface FurnitureFactory {
createChair(): Chair;
createSofa(): Sofa;
}
// 3. Concrete Factories
class VictorianFurnitureFactory implements FurnitureFactory {
createChair(): Chair { return new VictorianChair(); }
createSofa(): Sofa { return new VictorianSofa(); }
}
class ModernFurnitureFactory implements FurnitureFactory {
createChair(): Chair { return new ModernChair(); }
createSofa(): Sofa { return new ModernSofa(); }
}
// Client Code
function orderLivingRoom(factory: FurnitureFactory) {
const chair = factory.createChair();
const sofa = factory.createSofa();
chair.sitOn();
sofa.lieOn();
}
// Usage
console.log("Ordering Victorian Furniture:");
orderLivingRoom(new VictorianFurnitureFactory());
console.log("\nOrdering Modern Furniture:");
orderLivingRoom(new ModernFurnitureFactory());
Class Diagram
Factory Method vs Abstract Factory
- Factory Method: Creates exactly one type of product. Uses Inheritance (subclasses implement the factory method).
- Abstract Factory: Creates families of related products. Uses Composition (factories are injected into the client). It actually usually uses the Factory Method inside its methods to create the products.