Bird
Raised Fist0

Abstract Factory Pattern - Creating Families of Related Objects

LLDeasyInterview freq: common
Choose your preparation mode4 modes available
🏗️
Abstract Factory Pattern - Creating Families of Related Objects
Abstract Factory Pattern enables creation of families of related objects without specifying their concrete classes.
easyDesign Patterns - AppliedFreq: common
Prerequisites:OOP BasicsPolymorphism
⚙️
Functional Requirements
  • Provide an abstract factory interface declaring creation methods for each abstract product.
  • Implement concrete factories that produce concrete products belonging to a specific family.
  • Abstract products define interfaces for product types; concrete products implement these interfaces.
  • Client code uses only abstract factory and abstract product interfaces to remain decoupled from concrete classes.
  • Support easy addition of new product families by adding new concrete factories and products.
  • Ensure thread safety when factories are accessed concurrently by multiple threads.
👤
Use Cases
  • Client requests a family of related products without knowing their concrete classes.
  • Client switches between different product families by changing the factory instance.
  • Factories create related products that are compatible with each other.
  • Extending the system to add new product families without modifying existing client code.
  • Ensuring thread-safe creation of product instances if factories are shared across threads.
🧑‍💻
Actors
  • Client
  • AbstractFactory
  • ConcreteFactory
  • AbstractProduct
  • ConcreteProduct
❓
Clarifying Questions to Ask
  • How many concurrent threads will access the factories? Should factories be thread-safe singletons or instantiated per client?
  • Is there a pricing or configuration strategy that affects product creation?
  • Are products immutable after creation or do they require setters?
  • Should the client be able to switch factories at runtime dynamically?
  • What happens if a requested product type is not supported by a factory?
  • Are there any performance constraints on product creation?
Out of Scope
✗ Product lifecycle management beyond creation (e.g., caching, pooling).
✗ Complex product configuration or dependency injection frameworks.
✗ GUI or UI-specific product rendering details.
⚡
QPS Calculation
write qps100
read qps1000
rationaleEstimated QPS based on typical furniture product creation and retrieval in a medium scale application.
🖥️
Server Estimate
2
Two servers recommended for load balancing and high availability given QPS and data volume.
🔢
Enumerations
enum ProductType
CHAIR | SOFA | TABLE
Defines product categories to prevent typo bugs and enable exhaustive switch statements in factories.
enum FamilyType
MODERN | VICTORIAN | ART_DECO
Represents product family variants to enforce type safety and clear factory selection.
📦
AbstractFactory
0 fields
Declare creation methods for each abstract product type to be implemented by concrete factories.
Why thisAbstract class or interface allows defining a contract for product creation without binding to concrete classes, enabling flexibility and extensibility.
Why notUsing concrete classes would tightly couple client code to implementations, reducing flexibility and violating Open-Closed Principle.
public abstract Chair createChair()Creates an abstract Chair product.
public abstract Sofa createSofa()Creates an abstract Sofa product.
public abstract Table createTable()Creates an abstract Table product.
📦
ModernFurnitureFactory
0 fields
Concrete factory that creates modern style furniture products.
Why thisConcrete factory implements the abstract factory interface to produce a family of related products, ensuring compatibility.
Why notUsing a generic factory without family grouping would risk mixing incompatible products and reduce cohesion.
public Chair createChair()Creates a ModernChair instance.
public Sofa createSofa()Creates a ModernSofa instance.
public Table createTable()Creates a ModernTable instance.
📦
Chair
0 fields
Abstract product interface for Chair type furniture.
Why thisInterface defines contract for Chair products, allowing multiple implementations and polymorphism.
Why notUsing concrete classes would limit extensibility and violate Liskov Substitution Principle.
public abstract void sitOn()Defines behavior for sitting on the chair.
📦
ModernChair
0 fields
Concrete product implementing Chair interface for modern style.
Why thisProvides specific implementation details for modern style chairs.
Why notUsing a generic chair class would not capture style-specific behavior or appearance.
public void sitOn()Implements sitOn behavior specific to ModernChair.
📦
Client
1 fields
private AbstractFactory factory
Uses AbstractFactory interface to create families of related products without coupling to concrete classes.
Why thisClient depends on abstractions to remain decoupled and support switching factories dynamically.
Why notDirectly instantiating concrete products would tightly couple client to implementations, reducing flexibility.
public void setFactory(AbstractFactory factory)Sets the current factory to create products from.
public void createFurnitureSet()Creates a set of related furniture products using the current factory.
📦
Sofa
0 fields
Abstract product interface for Sofa type furniture.
Why thisDefines contract for Sofa products enabling multiple implementations.
Why notConcrete classes would limit extensibility and polymorphism.
public abstract void lieOn()Defines behavior for lying on the sofa.
📦
ModernSofa
0 fields
Concrete product implementing Sofa interface for modern style.
Why thisProvides modern style specific implementation for Sofa.
Why notGeneric sofa class would not capture style-specific behavior.
public void lieOn()Implements lieOn behavior specific to ModernSofa.
📦
Table
0 fields
Abstract product interface for Table type furniture.
Why thisDefines contract for Table products allowing multiple implementations.
Why notConcrete classes would reduce flexibility and extensibility.
public abstract void use()Defines behavior for using the table.
📦
ModernTable
0 fields
Concrete product implementing Table interface for modern style.
Why thisProvides modern style specific implementation for Table.
Why notGeneric table class would not capture style-specific behavior.
public void use()Implements use behavior specific to ModernTable.
🔗
Relationships
ModernFurnitureFactory──►Chair[1..1]
realizationConcreteFactory controls product creation; products can exist independently after creation.
ModernFurnitureFactory──►Sofa[1..1]
realizationConcreteFactory controls product creation; products can exist independently after creation.
ModernFurnitureFactory──►Table[1..1]
realizationConcreteFactory controls product creation; products can exist independently after creation.
Client──►AbstractFactory[1..1]
associationClient holds reference to AbstractFactory; factory can exist independently.
AbstractFactory──►Chair[1..1]
associationFactory creates Chair products; products exist independently after creation.
AbstractFactory──►Sofa[1..1]
associationFactory creates Sofa products; products exist independently after creation.
AbstractFactory──►Table[1..1]
associationFactory creates Table products; products exist independently after creation.
🗄️
FurnitureFactory
PK: familyType
familyType: FamilyTypefactoryId: UUIDfactoryName: StringcreatedAt: Timestamp
Stores metadata about furniture factories by family type.
🗄️
FurnitureProduct
PK: productType
productType: ProductTypeproductId: UUIDfactoryId: UUIDstyle: StringcreatedAt: Timestamp
Stores product instances created by factories.
🔌
CreateFurnitureSet
Request
{
  "factoryId": "UUID"
}
Response
{
  "status": "success|failure",
  "products": "List of product details"
}
Creates a set of related furniture products using the specified factory.
🔌
GetFactoryDetails
Request
{
  "factoryId": "UUID"
}
Response
{
  "factoryName": "String",
  "familyType": "FamilyType",
  "createdAt": "Timestamp"
}
Retrieves metadata about a specific furniture factory.
🔌
ListProductTypes
Request
{}
Response
{
  "productTypes": "List of ProductType enums"
}
Lists all supported product types.

Practice

(1/5)
1. In the Amazon Locker Service design, a LockerManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is it the correct choice?
easy
A. Singleton pattern, to ensure only one instance manages all lockers globally.
B. Factory pattern, because it controls object creation centrally.
C. Builder pattern, to incrementally construct LockerManager with configurations.
D. Prototype pattern, to clone LockerManager instances for scalability.

Solution

  1. Step 1: Identify the pattern from constructor and method

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single globally accessible instance.
  2. Step 2: Why Singleton fits this use case

    LockerManager must coordinate locker assignments centrally to avoid conflicts, so a single instance is necessary. Factory or Builder do not enforce single instance, Prototype is for cloning, which is not needed here.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
2. In the Online Stock Brokerage system, the TradeManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here and why is this the correct choice?
easy
A. Prototype pattern, to clone existing trade instances for faster processing.
B. Factory pattern, because it controls object creation centrally for different trade types.
C. Builder pattern, to incrementally construct complex trade objects with validation.
D. Singleton pattern, to ensure only one instance manages all trades and avoid inconsistent state.

Solution

  1. Step 1: Identify the pattern from constructor and method

    The private constructor prevents external instantiation, and the static synchronized getInstance() method ensures a single instance is created and accessed thread-safely.
  2. Step 2: Why Singleton fits this scenario

    TradeManager must coordinate all trades globally to maintain consistent state; multiple instances would cause conflicting trade states.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + static synchronized getInstance() -> Singleton [check]
Common Mistakes:
3. In designing a Vehicle abstraction, should it be an abstract class or an interface if it needs to hold state like speed and fuelLevel? Why?
easy
A. Interface, because Java 8+ interfaces can have default methods and fields.
B. Interface, because it allows multiple inheritance and enforces behavior contracts.
C. Abstract class, because it can hold shared state and provide default behavior implementations.
D. Abstract class, because it prevents any subclass from overriding methods.

Solution

  1. Step 1: Analyze state and behavior requirements

    Since Vehicle needs to hold mutable state like speed and fuelLevel, it requires fields and possibly default implementations that manage this state.
  2. Step 2: Compare abstract class vs interface capabilities

    Abstract classes can hold instance variables and provide default method implementations that access state. Interfaces cannot hold instance state (only constants) and default methods cannot manage mutable state effectively.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Stateful abstraction -> abstract class, not interface [check]
Hint: Stateful abstraction needs abstract class, not interface [check]
Common Mistakes:
4. In a vending machine using the State pattern, if the method selectItem() is not synchronized, which exact thread interleaving causes dispensing the same item twice?
medium
A. Thread 1 checks item availability -> true, context switch, Thread 2 checks availability -> true, both dispense item
B. Thread 1 and Thread 2 both wait on a lock, causing deadlock
C. Thread 1 updates inventory, Thread 2 reads old inventory before update
D. Thread 1 calls selectItem(), Thread 2 calls cancel(), both proceed concurrently

Solution

  1. Step 1: Identify the check-then-act race

    Without synchronization, both threads can read item availability as true before either decrements inventory.
  2. Step 2: Trace the interleaving

    Thread 1 checks availability -> true, context switch; Thread 2 checks availability -> true; both proceed to dispense, causing double dispense.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> double dispense [check]
Hint: Check-then-act without sync -> double dispense race [check]
Common Mistakes:
5. In a multi-threaded Java implementation of a parking lot using the Template Method pattern, the parkVehicle() method checks if a spot is available before assigning it. Without synchronization, which exact thread interleaving causes double-booking of the same spot?
medium
A. Thread 1 and Thread 2 both call parkVehicle() simultaneously and block each other.
B. Thread 1 releases a spot while Thread 2 is assigning, causing inconsistent state but no double-booking.
C. Thread 1 assigns spot, then Thread 2 checks availability and finds it occupied, so no double-booking.
D. Thread 1 checks isAvailable() -> true, context switch; Thread 2 checks isAvailable() -> true; both assign the same spot.

Solution

  1. Step 1: Trace check-then-act race

    Thread 1 calls isAvailable() and sees true, but before assigning, context switches.
  2. Step 2: Thread 2 also calls isAvailable() and sees true, then both assign the same spot concurrently.

  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Unsynchronized check-then-act allows double assignment [check]
Hint: Check-then-act without sync -> double booking [check]
Common Mistakes:
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