Bird
Raised Fist0

Factory Pattern - Object Creation Without Coupling the Caller

LLDeasyInterview freq: high
Choose your preparation mode4 modes available
🏗️
Factory Pattern - Object Creation Without Coupling the Caller
Decouple object creation from usage by encapsulating instantiation logic in a Factory class.
easyDesign Patterns - AppliedFreq: high
Prerequisites:OOP BasicsPolymorphism
⚙️
Functional Requirements
  • Factory must provide a method to create Product instances based on input parameters
  • Client must interact only with Product interface or abstract class
  • Factory should encapsulate all instantiation logic
  • Factory must be extensible to add new product types without modifying existing code (Open-Closed Principle)
  • Factory must be thread-safe to handle concurrent creation requests
  • Factory should handle invalid or unsupported product types by throwing exceptions or returning null
  • Product instances should be independent and not shared unless explicitly designed
👤
Use Cases
  • Client requests a Product without knowing concrete implementation
  • Factory creates and returns appropriate ConcreteProduct based on input
  • Client uses Product polymorphically without coupling to concrete classes
  • Factory can be extended to create new product types without modifying client
  • Handle invalid product type requests gracefully
  • Support concurrent client requests for product creation
🧑‍💻
Actors
  • Client (caller requesting objects)
  • Factory (creates objects)
  • Product (abstract/interface for created objects)
  • ConcreteProduct (specific implementations of Product)
❓
Clarifying Questions to Ask
  • How many concurrent threads will request product creation? Should the factory be thread-safe?
  • Is there a pricing or configuration strategy that affects product creation?
  • Should the factory support dynamic registration of new product types at runtime?
  • What should happen if an unsupported product type is requested?
  • Are product instances immutable or mutable after creation?
  • Is lazy initialization of products required or all products created eagerly?
Out of Scope
✗ Object lifecycle management beyond creation (e.g., caching, pooling)
✗ Complex dependency injection frameworks
✗ Product behavior implementation details beyond creation
✗ Persistence or database integration
⚡
QPS Calculation
expected qps1000
peak qps5000
average request size bytes512
daily request volume86400000
🖥️
Server Estimate
application servers5
database servers2
load balancers2
Estimates based on expected QPS and request size to ensure factory can handle concurrent requests with low latency.
🔢
Enumerations
enum ProductType
TYPE_A | TYPE_B | TYPE_C
Enum prevents typo bugs by using ProductType.TYPE_A instead of raw strings, enabling exhaustive switch statements and compile-time checks.
enum CreationStatus
SUCCESS | FAILURE | UNSUPPORTED_TYPE
Enum standardizes factory creation result codes, avoiding magic numbers or strings and enabling clear handling of creation outcomes.
📦
Product
1 fields
String name
Defines the common interface or abstract class for all products created by the factory, enabling polymorphic usage.
Why thisUsing an interface or abstract class allows polymorphism and flexibility in Java, enabling different implementations.
Why notUsing concrete classes directly couples client code to implementations, reducing flexibility and violating Open-Closed Principle.
public String getName()Returns the product's name.
public abstract void performOperation()Abstract method to be implemented by concrete products to perform product-specific behavior.
📦
ConcreteProductA
1 fields
String name
Concrete implementation of Product representing type A products.
Why thisConcrete classes implement specific behaviors for product types, enabling polymorphic use via Product interface.
Why notAvoid using a single monolithic class with conditionals; this reduces maintainability and violates Single Responsibility Principle.
public void performOperation()Implements product-specific operation for ConcreteProductA.
📦
ConcreteProductB
1 fields
String name
Concrete implementation of Product representing type B products.
Why thisSeparate concrete classes allow extension without modifying existing code, supporting Open-Closed Principle.
Why notUsing enums or flags inside a single class leads to complex conditionals and harder maintenance.
public void performOperation()Implements product-specific operation for ConcreteProductB.
📦
ProductFactory
1 fields
volatile static ProductFactory instance
Singleton factory responsible for creating Product instances without exposing concrete classes to clients, encapsulating instantiation logic.
Why thisSingleton pattern ensures a single factory instance, controlling resource usage and providing a global access point.
Why notCreating multiple factory instances can lead to inconsistent object creation and higher resource usage.
public static ProductFactory getInstance()Returns the singleton instance of ProductFactory using double-checked locking with volatile to prevent JVM instruction reordering.
public Product createProduct(ProductType type)Creates and returns a Product instance based on the specified ProductType.
📦
Client
0 fields
Uses the ProductFactory to obtain Product instances and interacts with them polymorphically without coupling to concrete implementations.
Why thisClient depends only on abstractions, enabling loose coupling and easier testing.
Why notDirectly instantiating concrete products couples client code to implementations, reducing flexibility.
public void useProduct(ProductType type)Requests a product from the factory and invokes its operations.
🔗
Relationships
Client──►ProductFactory[1..1]
associationClient does not manage lifecycle of ProductFactory singleton
ProductFactory──►Product[1..*]
associationProductFactory creates Product instances but does not own lifecycle after creation
ConcreteProductA──►Product[1..1]
inheritanceConcreteProductA is a subtype of Product
ConcreteProductB──►Product[1..1]
inheritanceConcreteProductB is a subtype of Product
🗄️
products
PK: product_type
product_id UUIDproduct_type VARCHARname VARCHARcreated_at TIMESTAMP
Stores product metadata created by the factory.
🗄️
product_requests
PK: client_id
request_id UUIDclient_id VARCHARproduct_type VARCHARrequest_timestamp TIMESTAMPstatus VARCHAR
Logs client requests for product creation.
🔌
POST
Create Product
Request
{
  "productType": "ProductType enum"
}
Response
{
  "productId": "UUID",
  "name": "String",
  "status": "CreationStatus enum"
}
Creates a product instance via the factory and returns creation status.
🔌
GET
Get Product
Request
{
  "productId": "UUID"
}
Response
{
  "productId": "UUID",
  "productType": "ProductType enum",
  "name": "String"
}
Retrieves product details by product ID.
🔌
GET
List Products
Request
{
  "productType": "optional ProductType enum"
}
Response
{
  "products": "List of product metadata"
}
Lists products optionally filtered by type.

Practice

(1/5)
1. In designing the User and Message classes for the messaging system, should User be an abstract class or an interface, and why?
easy
A. User should be an interface to allow multiple inheritance of user behaviors.
B. User should be an interface because it only defines behavior without state.
C. User should be an abstract class because it holds common user state like userId and username.
D. User should be an abstract class to enforce implementation of all methods in subclasses.

Solution

  1. Step 1: Analyze if User has state or just behavior

    User holds common state such as userId and username, which requires fields and possibly default implementations.
  2. Step 2: Determine if abstract class or interface fits state and behavior

    Abstract class supports shared state and partial implementation, while interface cannot hold instance state.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    User has common state -> abstract class fits better than interface [check]
Hint: Stateful base class -> abstract class, stateless -> interface [check]
Common Mistakes:
2. In the Restaurant Management System, should the MenuItem be designed as an abstract class or an interface? Consider that MenuItem has shared state like price and description, and behavior like calculateDiscount().
easy
A. Interface, because it allows multiple inheritance and enforces method signatures without state.
B. Abstract class, because it can hold shared state and provide default behavior implementations.
C. Interface, because Java 8+ interfaces can have default methods and fields for state.
D. Abstract class, because it forces subclasses to implement all methods explicitly.

Solution

  1. Step 1: Analyze state and behavior requirements

    MenuItem has shared state (price, description) and behavior (calculateDiscount), which interfaces cannot hold as fields.
  2. Step 2: Abstract class supports shared state and default behavior

    Abstract classes can have instance variables and method implementations, making them suitable for MenuItem.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Shared state + behavior -> abstract class [check]
Hint: Stateful base class -> abstract class, stateless contract -> interface [check]
Common Mistakes:
3. A class has a private constructor and a static synchronized getInstance() method that returns the single instance. Which design pattern is applied here and why is this the CORRECT use case?
easy
A. Singleton pattern, because it ensures only one instance exists and provides global access.
B. Factory Method pattern, because it controls object creation through a static method.
C. Builder pattern, because it constructs complex objects step-by-step.
D. Prototype pattern, because it clones existing instances to create new ones.

Solution

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

    The private constructor prevents external instantiation, and the static synchronized getInstance() method controls instance creation, which matches Singleton pattern characteristics.
  2. Step 2: Explain why Singleton fits this use case

    Singleton ensures a single instance with thread-safe access via synchronization, suitable for shared resources like configuration or logging.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized static getInstance() -> Singleton pattern [check]
Hint: Private constructor + static synchronized getInstance() -> Singleton [check]
Common Mistakes:
4. The notification system must support ElectricCar vehicles that require ChargingSpot notifications. What is the minimum design change to support this without modifying existing classes?
hard
A. Modify Vehicle class to add isElectric flag and add charging logic in existing Spot classes.
B. Create a new ElectricCar class and ChargingSpot class, then modify NotificationFactory to handle them.
C. Add ELECTRIC_CAR to VehicleType enum and CHARGING to SpotType enum; create ElectricCar subclass and update SpotCompatibility map.
D. Add charging logic inside existing NotificationChannel implementations with conditional checks for ElectricCar.

Solution

  1. Step 1: Identify extensibility requirements

    New vehicle and spot types must be added without modifying existing classes to respect OCP.
  2. Step 2: Apply minimal changes

    Adding new enum values and creating new subclasses allows extension without modifying existing class code; updating compatibility map centralizes new logic.
  3. Step 3: Eliminate other options

    Options B, C, and D modify existing classes or factory logic, violating OCP and risking class explosion or god-class anti-pattern.
  4. Final Answer:

    Option C -> Option C
  5. Quick Check:

    New enums and subclasses extend design without modifying existing classes [check]
Hint: Add enums + subclasses, avoid modifying existing classes [check]
Common Mistakes:
5. ElectricCar requires ChargingSpots in the parking lot system. What is the minimum change to support this without modifying existing classes?
hard
A. Add ELECTRIC_CAR to VehicleType, CHARGING to SpotType, create ElectricCar extending Vehicle, and update SpotCompatibility.COMPATIBILITY_MAP accordingly.
B. Modify Vehicle class to include a chargingRequired flag and update all spot checks.
C. Create a new ChargingSpot class and modify ParkingLot to handle it specially.
D. Add a new interface Chargeable and make ElectricCar implement it, changing existing spot logic.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and a subclass extends functionality without changing existing class code, respecting OCP.
  2. Step 2: Evaluate options

    Modify Vehicle class to include a chargingRequired flag and update all spot checks. modifies Vehicle, violating OCP. Create a new ChargingSpot class and modify ParkingLot to handle it specially. requires modifying ParkingLot, violating minimal change. Add a new interface Chargeable and make ElectricCar implement it, changing existing spot logic. adds interface but requires changing spot logic, violating minimal change.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New enums + subclass + compatibility map update -> minimal change [check]
Hint: Add enums + subclass + compatibility map, no existing class change [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