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
40 min ยท medium
medium

Design a system that creates different types of vehicles (Car, Truck, Bike) using a Factory Pattern. The system has 5 levels of vehicle complexity and 4 gates controlling access. Pricing depends on vehicle type and level. The caller should not depend on concrete vehicle classes.

  • There are 3 vehicle types: Car, Truck, Bike, each with different attributes.
  • Vehicles have 5 complexity levels affecting pricing.
  • 4 gates control vehicle entry and exit.
  • Pricing depends on vehicle type and complexity level.
  • The caller must not be coupled to concrete vehicle classes.
  • The system must be thread-safe for concurrent vehicle creation.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define Vehicle Abstraction
Design an abstraction for vehicles that captures common state and behavior.
๐Ÿ’ก Hint
Use an abstract class if you need to hold instance state like licensePlate and vehicleType.
Use an abstract class Vehicle with fields licensePlate (String), vehicleType (enum VehicleType), and complexityLevel (int). Abstract class is chosen because it holds shared instance STATE; interfaces cannot hold fields in Java.
Mid: Recognizes need for abstraction to avoid code duplication. Senior: Explains why abstract class is chosen over interface due to instance state and shared behavior.
โš ๏ธCommon Wrong Answer
Using interface Vehicle with fields leads to compilation errors since interfaces cannot hold instance state in Java.
Step 2
Implement Concrete Vehicle Classes
Create concrete vehicle classes for Car, Truck, and Bike inheriting from Vehicle.
๐Ÿ’ก Hint
Each concrete class extends Vehicle and adds specific attributes if needed.
Concrete classes Car, Truck, Bike extend abstract Vehicle - inheritance relationship with lifecycle ownership; Vehicles exist only as concrete subclasses.
Mid: Implements inheritance hierarchy correctly. Senior: Explains lifecycle ownership-Vehicle abstract class cannot be instantiated, concrete subclasses own their state.
โš ๏ธCommon Wrong Answer
Using Vehicle interface and casting to concrete classes causes ClassCastException at runtime and breaks Liskov Substitution Principle.
Step 3
Design VehicleFactory Interface and Implementation
Design a VehicleFactory interface and a concrete factory class to create vehicles without exposing concrete classes to the caller.
๐Ÿ’ก Hint
Use a factory method that returns Vehicle. Use enum VehicleType as input to avoid String typos.
Define VehicleFactory interface with method public Vehicle createVehicle(VehicleType type, int complexityLevel). Implement ConcreteVehicleFactory that implements VehicleFactory - realization relationship; factory encapsulates object creation.
Mid: Uses Factory Pattern to decouple caller from concrete classes. Senior: Explains why enum VehicleType is used instead of String to prevent runtime bugs and enable exhaustive switch.
โš ๏ธCommon Wrong Answer
Using String for vehicle type leads to runtime typo bugs and no compile-time checking.
Step 4
Ensure Thread-Safe Vehicle Creation
Make the factory thread-safe to handle concurrent vehicle creation requests.
๐Ÿ’ก Hint
Use synchronized keyword on createVehicle method or use thread-safe lazy initialization if factory is singleton.
Declare public synchronized Vehicle createVehicle(...) in ConcreteVehicleFactory to atomically create vehicles; prevents race conditions where multiple threads create inconsistent objects.
Mid: Uses synchronized method to ensure thread safety. Senior: Explains exact thread interleaving where without synchronized, two threads could create inconsistent vehicle states or duplicate IDs.
โš ๏ธCommon Wrong Answer
Not synchronizing createVehicle leads to race conditions causing inconsistent vehicle state or duplicate vehicle creation.
Step 5
Implement Pricing Strategy Based on Vehicle Type and Complexity
Design a pricing strategy that calculates price based on vehicle type and complexity level.
๐Ÿ’ก Hint
Use enum VehicleType with switch-case for pricing; consider Strategy pattern if extensibility needed.
Define PricingStrategy interface with method public double calculatePrice(Vehicle vehicle). Implement ConcretePricingStrategy using switch on VehicleType enum - enum enables exhaustive compile-time checks.
Mid: Implements pricing logic correctly. Senior: Explains why enum switch is preferred over String to avoid runtime bugs and enable IDE refactoring support.
โš ๏ธCommon Wrong Answer
Using if-else on String vehicleType leads to fragile code and runtime errors if typos occur.
๐Ÿ”Œ
API Design Challenge
Design an API for the VehicleFactory that allows clients to create vehicles by specifying type and complexity level without exposing concrete classes. Ensure the API supports extensibility for new vehicle types and thread-safe creation.
  • Use an enum VehicleType instead of String to avoid typos and enable exhaustive switch statements.
  • Define a VehicleFactory interface with a createVehicle method returning the abstract Vehicle type.
  • Consider synchronizing the createVehicle method or using thread-safe patterns if the factory is a singleton.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • abstract class Vehicle with instance state licensePlate, vehicleType (enum), complexityLevel
  • Concrete classes Car, Truck, Bike extend Vehicle with inheritance relationship
  • VehicleFactory interface with createVehicle method returning Vehicle
  • ConcreteVehicleFactory with synchronized createVehicle method for thread safety
  • Use of enum VehicleType instead of String for type safety
Good to Have - 30%
  • PricingStrategy interface with enum-based pricing implementation
  • Factory Pattern enforcing Open-Closed Principle
  • Composition between Vehicle and PricingStrategy
  • Explanation of lifecycle ownership in inheritance
  • Use of synchronized keyword with exact concurrency reasoning
Bonus - 10%
  • Double-checked locking if singleton factory implemented
  • Extensible factory supporting new vehicle types without modification
  • Use of volatile keyword if singleton factory used
  • Detailed concurrency scenario tracing thread interleaving
  • Use of Strategy pattern for pricing
Using String for VehicleType leads to runtime typo bugs and no compile-time checks, causing fragile code and potential runtime errors.
Using interface Vehicle with instance fields causes compilation errors because Java interfaces cannot hold instance state.
Not synchronizing createVehicle causes race conditions leading to inconsistent vehicle state or duplicate vehicle creation in concurrent environments.
Casting Vehicle interface to concrete classes breaks Liskov Substitution Principle and causes ClassCastException at runtime.
Using if-else chains on String instead of enum leads to fragile code, runtime bugs due to typos, and lack of IDE refactoring support.
โœ…
Model Answer
โ–ผ Reveal

This solution uses the Factory Pattern in Java to create vehicle objects without coupling the caller to concrete classes. An abstract Vehicle class holds shared state, and concrete subclasses implement specific vehicle types. A VehicleFactory interface defines a createVehicle method returning Vehicle, implemented by ConcreteVehicleFactory with synchronized method for thread safety. Pricing is handled via a PricingStrategy interface using enum-based switch-case logic. The design leverages Java-specific features like enums and abstract classes for type safety and extensibility.

  • Use abstract class Vehicle to hold shared instance state because interfaces cannot hold fields in Java.
  • Use enum VehicleType instead of String to prevent runtime typo bugs and enable exhaustive switch-case.
  • Implement VehicleFactory interface to decouple caller from concrete vehicle classes.
  • Synchronize createVehicle method in ConcreteVehicleFactory to ensure thread-safe vehicle creation.
  • Use PricingStrategy interface with enum-based switch for pricing calculation to allow extensibility and maintainability.
  • abstract class Vehicle holds shared instance state licensePlate, vehicleType (enum), complexityLevel - interfaces cannot hold state in Java.
  • Concrete classes Car, Truck, Bike extend Vehicle - inheritance with lifecycle ownership; concrete classes own their state.
  • VehicleFactory interface defines createVehicle method returning Vehicle - decouples caller from concrete classes.
  • ConcreteVehicleFactory implements VehicleFactory with synchronized createVehicle method - ensures thread-safe object creation.
  • Use enum VehicleType instead of String to prevent runtime typo bugs and enable exhaustive switch-case.
  • PricingStrategy interface with concrete implementation uses enum VehicleType switch for pricing calculation.
  • Factory Pattern enforces Open-Closed Principle (SOLID) by allowing new vehicle types without modifying caller code.
  • Synchronized method createVehicle prevents race conditions during concurrent vehicle creation.
  • Composition relationship between Vehicle and PricingStrategy allows flexible pricing without modifying Vehicle classes.
  • Use of enum and abstract class leverages Java-specific language features for type safety and code reuse.

Practice

(1/5)
1. In designing a Vehicle abstraction for a parking system, should Vehicle be an abstract class or an interface if it needs to hold state like licensePlate? Why?
easy
A. Interface, because it enforces method signatures without implementation or state, which is ideal for all vehicles.
B. Abstract class, because it forces all subclasses to implement all methods explicitly.
C. Interface, because Java 8+ allows default methods that can hold state variables safely.
D. Abstract class, because it can hold shared state like licensePlate and provide common behavior implementations.

Solution

  1. Step 1: Identify state holding needs

    licensePlate is shared state, which interfaces cannot hold as fields.
  2. Step 2: Evaluate options

    Abstract classes can hold state and provide default behavior; interfaces cannot hold instance fields, only constants.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Abstract class holds shared state like licensePlate [check]
Hint: State needs abstract class, interfaces only declare behavior [check]
Common Mistakes:
2. In a multi-threaded parking lot system, if parkVehicle() is not synchronized, which exact sequence of Thread 1 and Thread 2 calls causes double-booking of the same spot?
medium
A. Thread 1 checks spot availability -> true, context switch; Thread 2 checks spot availability -> true; both park simultaneously.
B. Thread 1 parks vehicle, Thread 2 waits for Thread 1 to finish, then parks vehicle.
C. Thread 1 parks vehicle, Thread 2 parks vehicle immediately after without checking availability.
D. Thread 1 releases spot, Thread 2 parks vehicle before Thread 1 finishes updating status.

Solution

  1. Step 1: Identify race condition

    Without synchronization, both threads can read spot availability as true before either marks it occupied.
  2. Step 2: Trace exact interleaving

    Thread 1: isAvailable() -> true, context switch; Thread 2: isAvailable() -> true; both proceed to park, causing double-booking.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Check-then-act gap without synchronization -> double-booking [check]
Hint: Check availability then park must be atomic to avoid double-booking [check]
Common Mistakes:
3. You want to add a WeekendFeeStrategy to calculate extra fees for weekend playback in the current music library design. Which approach requires the minimum change while respecting SOLID principles?
medium
A. Modify the existing FeeCalculator class to add weekend fee logic inside its method.
B. Create a new WeekendFeeStrategy class implementing the existing FeeStrategy interface and inject it where needed.
C. Add a boolean flag isWeekend to the Track class and calculate fees there.
D. Create a subclass WeekendFeeCalculator extending FeeCalculator and override the fee method.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires adding new behavior without modifying existing code.
  2. Step 2: Evaluate options against OCP

    Create a new WeekendFeeStrategy class implementing the existing FeeStrategy interface and inject it where needed. adds a new strategy class implementing FeeStrategy, no existing class modified, respecting OCP and Dependency Inversion Principle.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New strategy class -> no existing code change -> OCP respected [check]
Hint: OCP: add new class, don't modify existing [check]
Common Mistakes:
4. In the auction system, the placeBid() method checks if the auction is still open before accepting a bid. Without synchronizing placeBid(), which exact thread interleaving causes two threads to accept bids after the auction closes, resulting in inconsistent state?
medium
A. Thread 1 reads auction open -> false; Thread 2 reads auction open -> true; both reject bids.
B. Thread 1 and Thread 2 both wait on a lock; no bids accepted until lock released.
C. Thread 1 writes bid; Thread 2 reads bid; no race condition occurs because writes are atomic.
D. Thread 1 reads auction open -> true; context switch before bid recorded; Thread 2 reads auction open -> true; both record bids after auction closed.

Solution

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

    Without synchronization, Thread 1 reads auction open as true but is preempted before recording the bid.
  2. Step 2: Thread 2 reads auction open as true and proceeds to record bid as well, both bypassing the closed state check.

  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Unsynchronized check-then-act -> double acceptance after close [check]
Hint: Check-then-act without sync -> race condition double accept [check]
Common Mistakes:
5. In a parking lot system, if the parkVehicle() method is NOT synchronized, which exact sequence of Thread 1 and Thread 2 causes double-booking of the same spot?
medium
A. Thread 1 parks vehicle, Thread 2 waits for Thread 1 to release lock before parking.
B. Thread 1 parks vehicle, Thread 2 parks vehicle after Thread 1 finishes.
C. Thread 1 checks spot availability -> true, context switch; Thread 2 checks spot availability -> true; both park simultaneously.
D. Thread 1 and Thread 2 both wait on a condition variable before parking.

Solution

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

    Without synchronization, Thread 1 reads spot as available (true) but before it marks it occupied, context switches to Thread 2.
  2. Step 2: Thread 2 also reads spot as available and proceeds to park

    Both threads proceed to park the vehicle, causing double-booking.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Unsynchronized check-then-act -> both threads see available -> double-booking [check]
Hint: Unsynchronized check-then-act -> double-booking race [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