Bird
Raised Fist0
LLDsystem_design~7 mins

Abstract Factory pattern in LLD - System Design Guide

Choose your learning style10 modes available
Problem Statement
When a system needs to create families of related objects without specifying their concrete classes, hardcoding object creation leads to rigid code that is difficult to extend or modify. This causes tight coupling between client code and specific implementations, making it hard to support new product variants or platforms without changing existing code.
Solution
The Abstract Factory pattern provides an interface to create families of related objects without specifying their concrete classes. It defines abstract factory interfaces and concrete factory classes that produce related objects, allowing the client to work with abstract types. This decouples the client from specific implementations and enables easy extension by adding new factories and products.
Architecture
Client
↓
ConcreteFactoryA
(implements AF)
↓
ProductA1
(implements

This diagram shows the client using an abstract factory interface to create related products. Concrete factories implement this interface to produce specific product variants.

Trade-offs
✓ Pros
→
Decouples client code from concrete classes, improving flexibility.
→
Supports easy addition of new product families without modifying existing code.
→
Ensures that related products are used together, maintaining consistency.
✗ Cons
→
Increases the number of classes and interfaces, adding complexity.
→
Can be overkill for simple systems with few product variants.
→
Requires upfront design to define abstract interfaces and factories.
Use when a system must create multiple families of related objects and needs to ensure that products from the same family are used together, especially when the system must support multiple platforms or variants.
Avoid when the system only needs to create a few unrelated objects or when product variants are unlikely to change, as the added complexity is not justified.
Real World Examples
Apple
Uses Abstract Factory to create UI components that adapt to different platforms like macOS and iOS, ensuring consistent look and feel.
Microsoft
Uses Abstract Factory in Windows to create families of related GUI elements for different themes and accessibility settings.
Google
Uses Abstract Factory in Android to generate UI widgets that vary by device type and OS version.
Code Example
Before applying Abstract Factory, the Application class directly creates platform-specific buttons, causing tight coupling and hard-to-maintain code. After applying Abstract Factory, the Application depends on an abstract factory interface to create buttons, allowing easy extension to new platforms by adding new factories without changing Application code.
LLD
### Before: Without Abstract Factory
class WindowsButton:
    def click(self):
        print("Windows button clicked")

class MacOSButton:
    def click(self):
        print("MacOS button clicked")

class Application:
    def __init__(self, os_type):
        if os_type == "Windows":
            self.button = WindowsButton()
        else:
            self.button = MacOSButton()

    def click_button(self):
        self.button.click()

app = Application("Windows")
app.click_button()

### After: With Abstract Factory
from abc import ABC, abstractmethod

class Button(ABC):
    @abstractmethod
    def click(self):
        pass

class WindowsButton(Button):
    def click(self):
        print("Windows button clicked")

class MacOSButton(Button):
    def click(self):
        print("MacOS button clicked")

class GUIFactory(ABC):
    @abstractmethod
    def create_button(self) -> Button:
        pass

class WindowsFactory(GUIFactory):
    def create_button(self) -> Button:
        return WindowsButton()

class MacOSFactory(GUIFactory):
    def create_button(self) -> Button:
        return MacOSButton()

class Application:
    def __init__(self, factory: GUIFactory):
        self.button = factory.create_button()

    def click_button(self):
        self.button.click()

factory = WindowsFactory()
app = Application(factory)
app.click_button()
OutputSuccess
Alternatives
Factory Method
Factory Method creates one product per method and relies on subclassing, while Abstract Factory creates families of related products through multiple factory methods.
Use when: Choose Factory Method when you need to create one product type with variations, and Abstract Factory when you need to create multiple related products.
Builder
Builder focuses on constructing a complex object step-by-step, while Abstract Factory focuses on creating families of related objects.
Use when: Choose Builder when object construction is complex and needs stepwise control, Abstract Factory when you need to create related product families.
Summary
Abstract Factory decouples client code from concrete classes by creating families of related objects through abstract interfaces.
It ensures consistency among products and supports easy extension to new product variants or platforms.
The pattern adds complexity and should be used when multiple related products need to be created together.

Practice

(1/5)
1. What is the main purpose of the Abstract Factory pattern in system design?
easy
A. To create families of related objects without specifying their concrete classes
B. To allow direct instantiation of concrete classes
C. To enforce a single instance of a class
D. To simplify database queries

Solution

  1. Step 1: Understand the role of Abstract Factory

    The Abstract Factory pattern is designed to create related objects without exposing their concrete classes.
  2. Step 2: Compare options with the pattern's purpose

    To create families of related objects without specifying their concrete classes correctly describes this purpose, while others describe different patterns or unrelated concepts.
  3. Final Answer:

    To create families of related objects without specifying their concrete classes -> Option A
  4. Quick Check:

    Abstract Factory = Create related objects [OK]
Hint: Abstract Factory creates related objects without concrete classes [OK]
Common Mistakes:
  • Confusing Abstract Factory with Singleton pattern
  • Thinking it creates only one object
  • Mixing it up with Builder or Factory Method
2. Which of the following is the correct way to declare an Abstract Factory interface in a typical object-oriented design?
easy
A. var AbstractFactory = { create: function() { return ProductA; } }
B. class AbstractFactory { new ProductA(); new ProductB(); }
C. function AbstractFactory() { return new ProductA(); }
D. interface AbstractFactory { createProductA(): ProductA; createProductB(): ProductB; }

Solution

  1. Step 1: Identify correct interface syntax

    Abstract Factory is usually declared as an interface with methods to create related products.
  2. Step 2: Analyze each option

    interface AbstractFactory { createProductA(): ProductA; createProductB(): ProductB; } correctly declares an interface with creation methods. Options A, B, and C do not follow interface or abstract factory conventions.
  3. Final Answer:

    interface AbstractFactory { createProductA(): ProductA; createProductB(): ProductB; } -> Option D
  4. Quick Check:

    Abstract Factory interface = interface AbstractFactory { createProductA(): ProductA; createProductB(): ProductB; } [OK]
Hint: Abstract Factory uses interface with creation methods [OK]
Common Mistakes:
  • Using concrete class instead of interface
  • Returning product instances directly in constructor
  • Confusing factory function with abstract factory interface
3. Given the following code snippet using Abstract Factory pattern, what will be the output?
class ModernFactory {
  createChair() { return 'Modern Chair'; }
  createSofa() { return 'Modern Sofa'; }
}
class VictorianFactory {
  createChair() { return 'Victorian Chair'; }
  createSofa() { return 'Victorian Sofa'; }
}
function client(factory) {
  console.log(factory.createChair());
  console.log(factory.createSofa());
}
client(new VictorianFactory());
medium
A. Victorian Chair\nVictorian Sofa
B. Modern Chair\nModern Sofa
C. Error: factory methods not found
D. undefined\nundefined

Solution

  1. Step 1: Identify which factory is used

    The client function is called with new VictorianFactory(), so VictorianFactory methods will be used.
  2. Step 2: Trace method calls and outputs

    VictorianFactory's createChair() returns 'Victorian Chair' and createSofa() returns 'Victorian Sofa'. These are printed.
  3. Final Answer:

    Victorian Chair Victorian Sofa -> Option A
  4. Quick Check:

    VictorianFactory output = Victorian Chair\nVictorian Sofa [OK]
Hint: Check which factory instance is passed to client [OK]
Common Mistakes:
  • Assuming ModernFactory is used instead
  • Confusing method names or return values
  • Expecting errors due to missing interface
4. In the following Abstract Factory implementation, what is the main issue causing a runtime error?
class Factory {
  createProduct() {
    return new Product();
  }
}
class Product {}
const factory = new Factory();
const product = factory.createProduct();
console.log(product.name.toUpperCase());
medium
A. Missing interface declaration for Factory
B. Product class does not have a 'name' property, causing undefined access
C. Factory class cannot instantiate Product directly
D. createProduct method is not returning an object

Solution

  1. Step 1: Analyze the Product class and usage

    The Product class is empty and does not define a 'name' property.
  2. Step 2: Understand the console.log statement

    Accessing product.name returns undefined, and calling toUpperCase() on it causes a TypeError runtime error.
  3. Final Answer:

    Product class does not have a 'name' property, causing undefined access -> Option B
  4. Quick Check:

    Accessing missing property = Product class does not have a 'name' property, causing undefined access [OK]
Hint: Check if accessed properties exist on created objects [OK]
Common Mistakes:
  • Thinking Factory cannot instantiate Product
  • Expecting interface is mandatory at runtime
  • Assuming createProduct returns null or undefined
5. You are designing a UI toolkit that supports multiple themes (Light and Dark). Using the Abstract Factory pattern, which design ensures that all UI components (Button, Checkbox) are consistent with the selected theme?
hard
A. Create Buttons and Checkboxes directly in client code based on theme
B. Use a single factory that creates default Buttons and Checkboxes ignoring theme
C. Create separate factories for Light and Dark themes, each producing themed Buttons and Checkboxes
D. Use a factory that creates only Buttons and let client create Checkboxes

Solution

  1. Step 1: Understand the need for consistency

    Abstract Factory helps create families of related objects that match a theme or style.
  2. Step 2: Evaluate design options

    Create separate factories for Light and Dark themes, each producing themed Buttons and Checkboxes creates separate factories for each theme, ensuring all components are consistent. Other options break consistency or delegate creation improperly.
  3. Final Answer:

    Create separate factories for Light and Dark themes, each producing themed Buttons and Checkboxes -> Option C
  4. Quick Check:

    Theme consistency = Separate factories [OK]
Hint: Use one factory per theme to keep components consistent [OK]
Common Mistakes:
  • Mixing themes in one factory
  • Creating components directly in client code
  • Partial factory implementations missing products
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard