Skip to content
Low Level Design Mastery Logo
LowLevelDesign Mastery

Abstract Factory Pattern

Create families of related objects - ensure compatibility across product families!

Now let’s dive into the Abstract Factory Pattern - a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

Imagine you’re ordering a complete meal from a restaurant. You want everything to match - Italian restaurant gives you Italian appetizer, Italian main course, and Italian dessert. The Abstract Factory Pattern works the same way!

The Abstract Factory Pattern lets you create families of related objects. Instead of creating individual objects, you create a factory that produces a complete set of compatible objects.

What’s the Use of Abstract Factory Pattern?

Section titled “What’s the Use of Abstract Factory Pattern?”

The Abstract Factory Pattern is useful when:

  1. You need families of related objects - Objects that must work together
  2. You want to ensure compatibility - Objects from same family are compatible
  3. You need to switch families - Easy to switch between different families
  4. You want to hide implementation - Client doesn’t know concrete classes
  5. You need consistency - All objects in a family follow same style/theme

What Happens If We Don’t Use Abstract Factory Pattern?

Section titled “What Happens If We Don’t Use Abstract Factory Pattern?”

Without the Abstract Factory Pattern, you might:

  • Create incompatible objects - Mix objects from different families
  • Scatter creation logic - Object creation logic spread everywhere
  • Violate consistency - Objects don’t match or work together
  • Make it hard to switch families - Need to modify code everywhere
  • Tight coupling - Client code depends on concrete classes

Let’s start with a super simple example that anyone can understand!

Diagram

Here’s how the Abstract Factory Pattern works in practice - showing how families of objects are created:

sequenceDiagram
    participant Client
    participant Factory as AbstractFactory
    participant ItalianFactory
    participant Products as Italian Products
    
    Client->>Factory: getFactory("italian")
    activate Factory
    Factory->>ItalianFactory: create ItalianFactory
    activate ItalianFactory
    ItalianFactory-->>Factory: factory instance
    deactivate ItalianFactory
    Factory-->>Client: ItalianFactory
    deactivate Factory
    
    Client->>ItalianFactory: create_appetizer()
    activate ItalianFactory
    ItalianFactory->>Products: new ItalianAppetizer()
    Products-->>ItalianFactory: Bruschetta
    ItalianFactory-->>Client: ItalianAppetizer
    deactivate ItalianFactory
    
    Client->>ItalianFactory: create_main()
    activate ItalianFactory
    ItalianFactory->>Products: new ItalianMain()
    Products-->>ItalianFactory: Margherita Pizza
    ItalianFactory-->>Client: ItalianMain
    deactivate ItalianFactory
    
    Client->>ItalianFactory: create_dessert()
    activate ItalianFactory
    ItalianFactory->>Products: new ItalianDessert()
    Products-->>ItalianFactory: Tiramisu
    ItalianFactory-->>Client: ItalianDessert
    deactivate ItalianFactory
    
    Note over Client,Products: All products from<br/>same Italian family!

You’re building a pizza restaurant system that serves complete meals. Each meal has an appetizer, main course, and dessert. You want to ensure all items in a meal match (Italian meal = Italian appetizer + Italian main + Italian dessert). Without Abstract Factory Pattern:

Problems:

  • Can mix incompatible objects from different families
  • Creation logic scattered
  • Hard to ensure consistency
  • Need to modify code to add new families
classDiagram
    class PizzaMealFactory {
        <<abstract>>
        +create_appetizer() Appetizer
        +create_main() MainCourse
        +create_dessert() Dessert
    }
    class ItalianFactory {
        +create_appetizer() ItalianAppetizer
        +create_main() ItalianMain
        +create_dessert() ItalianDessert
    }
    class AmericanFactory {
        +create_appetizer() AmericanAppetizer
        +create_main() AmericanMain
        +create_dessert() AmericanDessert
    }
    class Appetizer {
        <<abstract>>
        +serve() str
    }
    class MainCourse {
        <<abstract>>
        +serve() str
    }
    class Dessert {
        <<abstract>>
        +serve() str
    }
    class ItalianAppetizer {
        +serve() str
    }
    class ItalianMain {
        +serve() str
    }
    class ItalianDessert {
        +serve() str
    }
    class AmericanAppetizer {
        +serve() str
    }
    class AmericanMain {
        +serve() str
    }
    class AmericanDessert {
        +serve() str
    }
    
    PizzaMealFactory <|-- ItalianFactory : implements
    PizzaMealFactory <|-- AmericanFactory : implements
    PizzaMealFactory ..> Appetizer : creates
    PizzaMealFactory ..> MainCourse : creates
    PizzaMealFactory ..> Dessert : creates
    Appetizer <|-- ItalianAppetizer : implements
    Appetizer <|-- AmericanAppetizer : implements
    MainCourse <|-- ItalianMain : implements
    MainCourse <|-- AmericanMain : implements
    Dessert <|-- ItalianDessert : implements
    Dessert <|-- AmericanDessert : implements
    
    note for PizzaMealFactory "Creates families of\ncompatible objects"
    note for ItalianFactory "All products are Italian"
    note for AmericanFactory "All products are American"

Now let’s see a realistic software example - a UI framework that needs to create families of UI components (buttons, dialogs, menus) that match the operating system theme.

You’re building a cross-platform UI framework. Each OS (Windows, macOS, Linux) has different UI components. You need to ensure all components in an application match the OS theme. Without Abstract Factory Pattern:

Problems:

  • Can mix incompatible UI components from different OS
  • Creation logic scattered
  • Hard to ensure consistency
  • Need to modify code to add new OS

There are several ways to implement the Abstract Factory Pattern:

Basic implementation with abstract factory interface:

Add a provider to get the right factory:


Use Abstract Factory Pattern when:

You need families of related objects - Objects that must work together
You want to ensure compatibility - Objects from same family are compatible
You need to switch families - Easy to switch between different families
You want to hide implementation - Client doesn’t know concrete classes
You need consistency - All objects in a family follow same style/theme

Don’t use Abstract Factory Pattern when:

Objects are independent - If objects don’t need to be compatible
Only one product type - If you only need one type of product
Simple object creation - If creation is straightforward
Over-engineering - Don’t add complexity for simple cases


Mistake 1: Mixing Products from Different Families

Section titled “Mistake 1: Mixing Products from Different Families”

Mistake 2: Not Using Abstract Factory When Needed

Section titled “Mistake 2: Not Using Abstract Factory When Needed”

  1. Ensures Compatibility - All objects from same factory are compatible
  2. Easy Family Switching - Change factory to switch entire family
  3. Consistency - All objects follow same style/theme
  4. Decoupling - Client doesn’t know concrete classes
  5. Extensibility - Easy to add new families without modifying existing code

Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects without specifying their concrete classes.

  • Families of related objects - Objects that must work together
  • Ensure compatibility - Objects from same family are compatible
  • Easy family switching - Change factory to switch entire family
  • Consistency - All objects follow same style/theme
  • Hide implementation - Client doesn’t know concrete classes
  1. Define abstract products - Interfaces for product types
  2. Define abstract factory - Interface for creating product families
  3. Create concrete products - Implementations for each family
  4. Create concrete factories - Implementations for each family
  5. Use factory - Client uses factory to create compatible products
Client → AbstractFactory → Product Family
  • Abstract Factory - Interface for creating product families
  • Concrete Factory - Creates products for specific family
  • Abstract Products - Interfaces for product types
  • Concrete Products - Implementations for each family
  • Client - Uses factory to create products
class UIFactory(ABC):
@abstractmethod
def create_button(self): pass
@abstractmethod
def create_dialog(self): pass
class WindowsFactory(UIFactory):
def create_button(self):
return WindowsButton()
def create_dialog(self):
return WindowsDialog()
# Usage
factory = WindowsFactory()
button = factory.create_button() # Windows
dialog = factory.create_dialog() # Windows - compatible!

✅ Need families of related objects
Objects must be compatible
✅ Need to switch entire families
✅ Need consistency across objects
✅ Want to hide implementation

Objects are independent
❌ Only one product type
❌ Simple object creation
❌ Over-engineering simple cases

  • Abstract Factory = Creates families of compatible objects
  • Family = Set of related products that work together
  • Compatibility = All products from same factory are compatible
  • Benefit = Ensures consistency and compatibility
  • Use Case = UI frameworks, theme systems, cross-platform apps
class AbstractFactory(ABC):
@abstractmethod
def create_a(self): pass
@abstractmethod
def create_b(self): pass
class Factory1(AbstractFactory):
def create_a(self):
return A1()
def create_b(self):
return B1()
# Usage
factory = Factory1()
a = factory.create_a() # A1
b = factory.create_b() # B1 - compatible!
  • Abstract Factory Pattern creates families of compatible objects
  • It ensures consistency within families
  • Use it when objects must work together
  • Don’t use it for independent object creation
  • It’s more complex than Factory Pattern - use when needed!

What to say:

“Abstract Factory Pattern is a creational design pattern that provides an interface for creating families of related or dependent objects. It ensures all objects created by a factory are compatible and work together.”

Why it matters:

  • Shows you understand the fundamental purpose
  • Demonstrates knowledge of when to use it
  • Indicates you can explain concepts clearly

Must explain:

  • Factory Pattern: Creates one type of product
  • Abstract Factory Pattern: Creates families of related products
  • Abstract Factory: Ensures compatibility within families

Example to give:

Factory Pattern creates individual products like ‘create a pizza’. Abstract Factory Pattern creates families like ‘create a complete Italian meal’ - ensuring appetizer, main course, and dessert all match the Italian theme.”

Must mention:

  • Families of related objects - Objects that must work together
  • Ensure compatibility - Objects from same family are compatible
  • Switch families - Easy to switch between different families
  • Consistency - All objects follow same style/theme

Example scenario to give:

“I’d use Abstract Factory Pattern when building a cross-platform UI framework. Each OS (Windows, Mac, Linux) has different UI components. I need to ensure all components in an application match the OS theme - Windows button with Windows dialog, not Mac dialog.”

Benefits to mention:

  • Compatibility - All products from same factory are compatible
  • Consistency - All objects follow same style/theme
  • Easy switching - Change factory to switch entire family
  • Decoupling - Client doesn’t know concrete classes

Trade-offs to acknowledge:

  • Complexity - More complex than Factory Pattern
  • Over-engineering - Can be overkill for simple cases
  • Many classes - Requires many classes (factories + products)

Q: “What’s the difference between Abstract Factory and Factory Pattern?”

A:

Factory Pattern creates individual products based on input. Abstract Factory Pattern creates families of related products. Factory Pattern: ‘create a pizza’. Abstract Factory Pattern: ‘create a complete Italian meal’ - ensuring all products match.”

Q: “When would you use Abstract Factory vs Factory Pattern?”

A:

“I use Factory Pattern when I need to create individual products - like creating different types of pizzas. I use Abstract Factory Pattern when I need families of compatible objects - like creating UI components that must match the OS theme, or creating complete meals where all items must match the cuisine style.”

Q: “How does Abstract Factory ensure compatibility?”

A:

“Abstract Factory ensures compatibility by having each concrete factory create all products for a specific family. For example, WindowsUIFactory creates WindowsButton, WindowsDialog, and WindowsMenu - all Windows components. The client uses the same factory for all products, guaranteeing they’re from the same family and compatible.”

Before your interview, make sure you can:

  • Define Abstract Factory Pattern clearly in one sentence
  • Distinguish from Factory Pattern
  • Explain when to use it (with examples)
  • Describe how it ensures compatibility
  • Implement Abstract Factory Pattern from scratch
  • Compare with other creational patterns
  • List benefits and trade-offs
  • Identify common mistakes
  • Give 2-3 real-world examples
  • Discuss when NOT to use it

Remember: Abstract Factory Pattern creates families of compatible objects - ensuring consistency and compatibility within each family! 🏭