Bird
Raised Fist0

Why LLD Exists and What HLD Cannot Tell You

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
๐ŸŽฏ
Design a Parking Lot System to Illustrate Why LLD Exists and What HLD Cannot Tell You
40 min ยท medium
medium

Design a parking lot system with 5 levels, each having 4 gates. The system supports multiple vehicle types and a pricing structure that varies by vehicle and duration. It must handle concurrent vehicle entries and exits, enforce parking spot allocation rules, and allow future extensibility without modifying existing classes.

  • The parking lot has 5 levels, each with 4 entry/exit gates.
  • Vehicles can be of types: MOTORCYCLE, CAR, TRUCK; each requires different spot sizes.
  • Pricing varies by vehicle type and parking duration with hourly rates.
  • Concurrent vehicle entries and exits can happen at any gate simultaneously.
  • Parking spots have types: COMPACT, REGULAR, LARGE; vehicles can only park in compatible spots.
  • The system must allow adding new vehicle types and pricing rules without modifying existing code.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Define Vehicle and Spot Types Using Enums
Design enums for VehicleType and SpotType to represent fixed categories. Explain why enums are preferred over Strings in Java.
๐Ÿ’ก Hint
Use Java enum types to enforce type safety and enable exhaustive switch statements.
Use Java enums VehicleType and SpotType - enums provide compile-time type safety and exhaustive switch support; String would allow typos and runtime bugs.
Mid: Names enums for VehicleType and SpotType. Senior: Explains how enums enable exhaustive switch and prevent runtime typo bugs unlike String.
โš ๏ธCommon Wrong Answer
Using String constants for VehicleType/SpotType leads to runtime typo bugs and no compile-time exhaustive checks.
Step 2
Model Vehicle as an Abstract Class with State
Design a Vehicle abstract class with licensePlate and vehicleType fields. Justify why abstract class is chosen over interface in Java.
๐Ÿ’ก Hint
Abstract class can hold instance state; interfaces cannot hold fields in Java.
abstract class Vehicle(licensePlate:String, vehicleType:VehicleType) - abstract because it holds shared instance STATE; interface cannot hold fields in Java.
Mid: Uses abstract class Vehicle with fields. Senior: Explains interface cannot hold instance state, so abstract class is needed for shared fields.
โš ๏ธCommon Wrong Answer
Using interface Vehicle with fields is invalid in Java; leads to compilation errors and inability to hold state.
Step 3
Implement Thread-Safe Parking Spot Allocation
Design a synchronized method parkVehicle(Vehicle v) that atomically checks spot availability and assigns a spot. Explain the concurrency mechanism used.
๐Ÿ’ก Hint
Use synchronized boolean parkVehicle(Vehicle v) to atomically check-and-set isAvailable flag on Spot.
synchronized boolean parkVehicle(Vehicle v) - synchronized ensures atomic check-and-set of spot availability to prevent race conditions during concurrent parking.
Mid: Uses synchronized method for atomicity. Senior: Traces exact race condition where Thread 1 reads AVAILABLE, context switch, Thread 2 reads AVAILABLE, both park causing double-booking without synchronization.
โš ๏ธCommon Wrong Answer
Not synchronizing parkVehicle leads to race conditions where multiple threads assign the same spot concurrently.
Step 4
Design Pricing Strategy Using Interface and Polymorphism
Create a PricingStrategy interface with method calculatePrice(Duration d, VehicleType vt). Explain why interface is chosen here.
๐Ÿ’ก Hint
Interface defines behavior without state, allowing multiple pricing implementations adhering to Open/Closed principle.
interface PricingStrategy { double calculatePrice(Duration d, VehicleType vt); } - interface used because pricing strategies vary behaviorally and do not hold instance state.
Mid: Defines PricingStrategy interface. Senior: Explains interface enables Open/Closed principle by allowing new pricing strategies without modifying existing code.
โš ๏ธCommon Wrong Answer
Using abstract class for PricingStrategy with state violates Open/Closed principle and complicates adding new pricing rules.
Step 5
Ensure Extensibility with Composition over Inheritance
Explain how to extend the system to add new vehicle types or pricing rules without modifying existing classes, referencing SOLID principles and Java mechanisms.
๐Ÿ’ก Hint
Favor composition by injecting new PricingStrategy implementations; use enum extension patterns carefully.
Use composition to inject new PricingStrategy implementations and avoid modifying Vehicle or ParkingLot classes - adheres to Open/Closed principle; enums are final so new vehicle types require enum extension via new enum or alternative pattern.
Mid: Describes composition for extensibility. Senior: Explains Java enum finality, suggests composition and delegation to extend behavior without modifying existing classes.
โš ๏ธCommon Wrong Answer
Modifying existing Vehicle enum or classes to add new types breaks Open/Closed principle and requires recompilation of all dependent code.
๐Ÿ”Œ
API Design Challenge
Design the public APIs for the ParkingLot system to handle vehicle entry, exit, spot allocation, and pricing calculation. Ensure thread safety and extensibility.
  • Define clear method signatures for vehicle entry and exit that handle concurrency.
  • Use interfaces and enums to abstract pricing and vehicle types for extensibility.
  • Consider how to expose pricing calculation without exposing internal state.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • Use of Java enums for fixed categories (VehicleType, SpotType)
  • abstract class Vehicle with instance fields (licensePlate, vehicleType)
  • synchronized method for atomic parking spot allocation
  • PricingStrategy interface for pricing behavior
  • Composition for extensibility adhering to Open/Closed principle
Good to Have - 30%
  • Singleton ParkingLot with volatile instance and double-checked locking
  • Final fields for immutability in Vehicle and Spot
  • Explicit lifecycle ownership in composition relationships
Bonus - 10%
  • Use of concurrent collections or locks for fine-grained concurrency control
  • Design patterns like Strategy for pricing and Factory for vehicle creation
Using String for VehicleType/SpotType leads to runtime typo bugs and no compile-time checks, causing unpredictable failures.
Modifying existing Vehicle enum or classes to add new types breaks Open/Closed principle and requires recompilation of all dependent code.
Not synchronizing parkVehicle leads to race conditions where multiple threads assign the same spot concurrently, causing double-booking.
Using abstract class for PricingStrategy with state violates Open/Closed principle and complicates adding new pricing rules.
โœ…
Model Answer
โ–ผ Reveal

This design outlines a parking lot system emphasizing the importance of Low-Level Design (LLD) in Java. It uses enums for type safety, abstract classes for shared state, synchronized methods for concurrency control, interfaces for pricing strategies, and composition for extensibility. The design adheres to SOLID principles and Java concurrency best practices.

  • Use Java enums VehicleType and SpotType to prevent runtime errors and enable exhaustive switch statements.
  • Implement Vehicle as an abstract class to hold shared instance state, as interfaces cannot hold fields in Java.
  • Synchronize parkVehicle method to atomically check and assign parking spots, preventing race conditions.
  • Define PricingStrategy as an interface to allow multiple interchangeable pricing behaviors adhering to Open/Closed principle.
  • Apply composition over inheritance to add new vehicle types or pricing rules without modifying existing classes, respecting Java enum finality.
  • Implement ParkingLot as a thread-safe singleton using volatile instance and double-checked locking to avoid partially constructed instances.
  • Use final fields in Vehicle and Spot classes to ensure immutability and thread safety.
  • Maintain explicit lifecycle ownership through composition: ParkingLot owns Levels, Levels own Spots, Vehicles exist independently.
  • Prefer synchronized methods or blocks over coarse-grained locking to minimize contention and improve concurrency.
  • Avoid mutable static state to prevent shared mutable state bugs in concurrent environments.
  • Use Java enums for VehicleType and SpotType to ensure compile-time safety and exhaustive switch statements.
  • abstract class Vehicle holds shared instance state (licensePlate, vehicleType) - interface cannot hold fields in Java.
  • synchronized boolean parkVehicle(Vehicle v) method ensures atomic check-and-set of spot availability preventing race conditions.
  • PricingStrategy interface defines pricing behavior without state, enabling multiple interchangeable pricing implementations.
  • Composition over inheritance for extensibility: inject new PricingStrategy implementations to add pricing rules without modifying existing code.
  • ParkingLot implemented as a singleton with volatile instance and double-checked locking to prevent partially constructed instances in multithreaded access.
  • Use of final fields in Vehicle and Spot classes to ensure immutability where possible, aiding thread safety.
  • Explicit lifecycle ownership: ParkingLot composition owns Levels; Levels composition owns Spots; Vehicles are associated and exist independently.
  • Use of synchronized blocks or methods rather than coarse-grained locking to minimize contention and improve concurrency.
  • Avoid mutable static state to prevent shared mutable state bugs in concurrent environment.

Practice

(1/5)
1. In designing a Command interface in Java, should it be an abstract class or an interface, and why? Consider that commands may need to store state for undo functionality.
easy
A. Abstract class, because it allows sharing common state and default undo logic among commands
B. Abstract class, because interfaces cannot declare methods
C. Interface, because Java interfaces can have default methods to share code and state
D. Interface, because commands only declare behavior and state should be external

Solution

  1. Step 1: Analyze state requirements for undo

    Commands often need to store state (e.g., previous values) to support undo, which requires fields.
  2. Step 2: Compare interface vs abstract class in Java

    Interfaces cannot hold instance fields, so abstract classes are better to share common state and default undo logic.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports shared state and behavior for undo [check]
Hint: Use abstract class for shared state in commands [check]
Common Mistakes:
2. In the Meeting Scheduler system, a MeetingManager class has a private constructor and a static synchronized getInstance() method. Which design pattern is applied here, and why is this the correct choice for managing meeting schedules?
easy
A. Singleton pattern, to ensure only one instance manages all meeting schedules and avoids conflicting updates.
B. Factory pattern, because it creates different meeting types dynamically.
C. Builder pattern, to construct complex meeting objects step-by-step.
D. Prototype pattern, to clone existing meeting instances for recurring events.

Solution

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

    The private constructor prevents external instantiation, and the static synchronized getInstance() ensures a single shared instance, matching Singleton pattern characteristics.
  2. Step 2: Reason why Singleton fits MeetingManager

    MeetingManager must coordinate all meetings centrally to avoid conflicting schedules; multiple instances could cause inconsistent state.
  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:
3. In the Facebook OOP design, the User class has a private constructor and a static synchronized getInstance() method to ensure only one instance per user ID exists. Which design pattern is applied here and why is it the correct choice?
easy
A. Singleton Pattern, to ensure a single instance per user ID and control concurrent access.
B. Prototype Pattern, to clone existing User instances efficiently.
C. Builder Pattern, to construct complex User objects step-by-step.
D. Factory Pattern, because it creates objects without exposing the instantiation logic.

Solution

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

    The private constructor and static synchronized getInstance() method indicate Singleton usage to control instance creation.
  2. Step 2: Why Singleton fits here

    Singleton ensures only one User instance per user ID exists, preventing duplicate objects and managing concurrency safely.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Private constructor + synchronized getInstance() -> Singleton pattern [check]
Hint: Private constructor + synchronized getInstance() -> Singleton [check]
Common Mistakes:
4. You are designing a base class Vehicle that provides a template method for starting the engine and driving, but also maintains internal state like fuel level. Should Vehicle be an abstract class or an interface, and why?
easy
A. Abstract class, because it can hold shared state and provide default method implementations.
B. Interface, because it allows multiple inheritance and enforces method signatures without state.
C. Interface, because Java 8+ interfaces can have default methods and fields for state.
D. Abstract class, because interfaces cannot define any behavior or state.

Solution

  1. Step 1: Consider state management

    Since Vehicle maintains internal state like fuel level, it requires fields, which interfaces cannot hold.
  2. Step 2: Evaluate method implementations

    Abstract classes can provide default implementations for template methods, supporting the Template Method pattern.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Abstract class supports state and default behavior [check]
Hint: State needs abstract class, not interface [check]
Common Mistakes:
5. In a parking system without synchronization on parkVehicle(), which exact thread interleaving causes double-booking of the same spot?
medium
A. Thread 1 parks vehicle, Thread 2 waits until Thread 1 finishes, then parks another vehicle.
B. Thread 1 and Thread 2 both crash before parking, causing no booking.
C. Thread 1 checks spot availability -> true, context switch; Thread 2 checks spot availability -> true; both park simultaneously.
D. Thread 1 parks vehicle, Thread 2 reads spot as occupied and waits.

Solution

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

    Without synchronization, both threads read spot as available before either marks it occupied.
  2. Step 2: Trace interleaving

    Thread 1 reads availability true, context switch; Thread 2 reads availability true; both proceed to park, causing double-booking.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Unsynchronized check-then-act allows both threads to park same spot [check]
Hint: Check-then-act without sync -> 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