Bird
Raised Fist0

Parking Lot System

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
🏗️
Parking Lot System
Design a Parking Lot System with Spot Types, Entry/Exit Gates, and Pricing using robust OOP hierarchy
mediumLibrary and Catalog SystemsFreq: high
Prerequisites:OOP DesignSingleton Pattern
⚙️
Functional Requirements
  • Support multiple spot types: Compact, Large, Handicapped, Electric
  • Allow multiple entry and exit gates operating concurrently
  • Calculate parking fee based on spot type and duration
  • Prevent double booking of parking spots under concurrent access
  • Provide real-time spot availability status
  • Allow vehicle parking and unparking operations
  • Support extensibility for new spot types and pricing strategies
👤
Use Cases
  • Driver enters parking lot through Entry Gate
  • Driver parks vehicle in an appropriate Spot
  • Driver exits parking lot through Exit Gate
  • System calculates parking fee based on duration and spot type
  • Parking Attendant monitors spot availability and manages spot status
  • System handles concurrent vehicle entries and exits
🧑‍💻
Actors
  • Driver
  • Parking Attendant
  • Parking Lot System
  • Payment System
❓
Clarifying Questions to Ask
  • How many entry and exit gates are expected to operate concurrently?
  • Is pricing fixed per spot type or dynamic based on demand/time?
  • What happens if all spots are full? Is there a waiting queue?
  • Are vehicles allowed to switch spots after parking?
  • How to handle lost tickets or manual overrides by attendants?
Out of Scope
✗ Integration with external payment gateways
✗ Mobile app or UI design
✗ Vehicle tracking beyond parking lot boundaries
✗ Reservation system for future parking spots
🔢
Enumerations
enum SpotType
COMPACT | LARGE | HANDICAPPED | ELECTRIC
Enum prevents typo bugs by using SpotType.COMPACT instead of strings and enables exhaustive switch-case for spot-specific logic.
enum SpotStatus
AVAILABLE | OCCUPIED | RESERVED | OUT_OF_SERVICE
Encapsulates spot availability states to avoid invalid status values and supports clear state transitions.
enum VehicleType
MOTORCYCLE | CAR | TRUCK | ELECTRIC_CAR
Defines vehicle categories to enforce compatibility with spot types and pricing rules.
📦
ParkingLot
6 fields
private final String idprivate final String nameprivate final Map<SpotType, List<ParkingSpot>> spotsByTypeprivate final List<EntryGate> entryGatesprivate final List<ExitGate> exitGatesprivate final PricingStrategy pricingStrategy
Manages the entire parking lot including spots, gates, and pricing. Coordinates parking and unparking operations.
Why thisUsing synchronized methods in Java ensures thread safety for parking operations in a concurrent environment.
Why notAvoided using external distributed locks like Zookeeper to keep design simple and focused on single instance concurrency.
public synchronized boolean parkVehicle(Vehicle vehicle)Attempts to park the vehicle in an available compatible spot atomically.
public synchronized boolean unparkVehicle(Vehicle vehicle)Frees the spot occupied by the vehicle and calculates parking fee.
public Map<SpotType, Integer> getAvailableSpots()Returns count of available spots per spot type.
📦
ParkingSpot
4 fields
private final String spotIdprivate final SpotType spotTypeprivate volatile SpotStatus statusprivate volatile Vehicle currentVehicle
Represents a parking spot with type and status. Manages atomic parking and unparking of vehicles.
Why thisSynchronized methods and volatile variables ensure visibility and atomicity for spot status updates.
Why notAvoided using atomic variables alone as multiple fields need to be updated atomically.
public synchronized boolean parkVehicle(Vehicle vehicle)Atomically checks availability and assigns vehicle to spot.
public synchronized boolean unparkVehicle()Atomically frees the spot and clears assigned vehicle.
public boolean isAvailable()Returns true if spot status is AVAILABLE.
📦
Vehicle
2 fields
private final String licenseNumberprivate final VehicleType vehicleType
Represents a vehicle with type and unique license number.
Why thisImmutable fields ensure thread safety and consistency of vehicle data.
Why notAvoided mutable vehicle objects to prevent concurrency issues.
public VehicleType getVehicleType()Returns the vehicle type.
public String getLicenseNumber()Returns the license number.
📦
EntryGate
2 fields
private final String gateIdprivate final ParkingLot parkingLot
Handles vehicle entry requests and delegates parking to ParkingLot.
Why thisActs as a facade to encapsulate entry logic and concurrency control at ParkingLot.
Why notAvoided direct parking lot access by clients to centralize concurrency management.
public boolean enterVehicle(Vehicle vehicle)Processes vehicle entry and attempts to park it.
📦
ExitGate
2 fields
private final String gateIdprivate final ParkingLot parkingLot
Handles vehicle exit requests and delegates unparking and fee calculation.
Why thisCentralizes exit processing and fee calculation through ParkingLot.
Why notAvoided duplicating fee logic in multiple exit gates.
public double exitVehicle(Vehicle vehicle)Processes vehicle exit and returns parking fee.
📦
PricingStrategy
0 fields
Abstract pricing strategy interface to calculate parking fees based on spot type and duration.
Why thisStrategy pattern enables extensible pricing policies without modifying core logic.
Why notAvoided hardcoding pricing logic in ParkingLot to support future changes.
public abstract double calculateFee(SpotType spotType, long durationInMinutes)Calculates fee for given spot type and parking duration.
📦
FlatRatePricingStrategy
1 fields
private final Map<SpotType, Double> ratePerHour
Concrete pricing strategy implementing flat hourly rates per spot type.
Why thisSimple and predictable pricing suitable for many parking lots.
Why notAvoided complex dynamic pricing to keep initial design simple.
public double calculateFee(SpotType spotType, long durationInMinutes)Calculates fee by multiplying hourly rate with duration.
🔗
Relationships
ParkingLot◆──►ParkingSpot[1..*]
compositionParkingSpot lifecycle bound to ParkingLot; spots destroyed with lot
ParkingLot◆──►EntryGate[1..*]
compositionEntryGate lifecycle bound to ParkingLot
ParkingLot◆──►ExitGate[1..*]
compositionExitGate lifecycle bound to ParkingLot
ParkingLot◇──►PricingStrategy[1]
aggregationPricingStrategy can exist independently and be replaced
EntryGate──►ParkingLot[1]
associationEntryGate references ParkingLot without ownership
ExitGate──►ParkingLot[1]
associationExitGate references ParkingLot without ownership
🗄️
ParkingSpots
PK: spotId
spotId STRINGspotType STRINGstatus STRINGcurrentVehicleLicense STRING
Stores parking spot details and current occupancy.
🗄️
ParkingTransactions
PK: transactionId
transactionId STRINGvehicleLicense STRINGspotId STRINGentryTime TIMESTAMPexitTime TIMESTAMPfee DOUBLE
Records parking sessions and fees.
🔌
EnterParkingLot
Request
{
  "vehicleLicense": "string",
  "vehicleType": "string"
}
Response
{
  "success": "boolean",
  "assignedSpotId": "string",
  "message": "string"
}
Handles vehicle entry and assigns parking spot.
🔌
ExitParkingLot
Request
{
  "vehicleLicense": "string"
}
Response
{
  "success": "boolean",
  "fee": "double",
  "message": "string"
}
Processes vehicle exit and returns parking fee.
🔌
GetAvailableSpots
Request
{}
Response
{
  "availableSpots": "map<string, int>"
}
Returns count of available spots by type.

Practice

(1/5)
1. In designing the Meeting Scheduler, should the Attendee entity be modeled as an abstract class or an interface, considering that attendees can be both internal employees and external guests with different data and behaviors?
easy
A. Interface, because it enforces a fixed implementation and prevents state duplication.
B. Interface, because attendees only define behaviors without shared state, allowing multiple inheritance.
C. Abstract class, because it allows sharing common state like name and email while enabling method overrides.
D. Abstract class, because interfaces cannot have any methods related to scheduling conflicts.

Solution

  1. Step 1: Analyze state and behavior needs

    Attendee has shared state (name, email) and some common behavior, which favors abstract class to avoid duplicating fields.
  2. Step 2: Evaluate interface limitations

    Interfaces cannot hold state, so using interface would force duplication or external state holders, complicating design.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Shared state + behavior -> abstract class [check]
Hint: Shared state? Use abstract class, not interface [check]
Common Mistakes:
2. A class provides a createIterator() method that returns an object allowing traversal over its elements without exposing its internal data structure. Which design pattern is being applied and why is this the correct choice?
easy
A. Factory Method pattern, because it encapsulates object creation logic.
B. Decorator pattern, because it adds traversal behavior dynamically.
C. Iterator pattern, because it separates traversal logic from the collection's internal structure.
D. Composite pattern, because it treats individual and composite objects uniformly.

Solution

  1. Step 1: Identify the role of createIterator()

    This method returns an object that allows clients to traverse elements without exposing the collection's internal representation, which is the core intent of the Iterator pattern.
  2. Step 2: Eliminate other patterns

    Factory Method focuses on object creation, Decorator adds responsibilities dynamically, and Composite manages tree structures. None focus on traversal abstraction.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Iterator separates traversal from collection internals [check]
Hint: Iterator hides structure, exposes traversal [check]
Common Mistakes:
3. In designing an Observer interface in Java, should it be an abstract class or an interface, and why? Consider that observers only define a single method update() without shared state.
easy
A. Use an abstract class to allow future shared state and default method implementations.
B. Use an interface to allow multiple inheritance and keep observers lightweight without state.
C. Use an abstract class because interfaces cannot have methods with parameters.
D. Use an interface because Java interfaces cannot have any method implementations.

Solution

  1. Step 1: Analyze Observer requirements

    Observers only define update() without shared state, so no need for instance variables or default behavior.
  2. Step 2: Choose interface for flexibility

    Interfaces allow multiple inheritance and keep observers lightweight; abstract classes add unnecessary state and restrict inheritance.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Observer interface with single method and no state -> interface preferred [check]
Hint: Observer has no state, so interface enables flexible multiple inheritance [check]
Common Mistakes:
4. In LinkedIn's ConnectionManager, the method addConnection(User a, User b) checks if users are already connected before adding. Without synchronizing this method, what exact thread interleaving causes a double connection to be created?
medium
A. Thread 1 checks isConnected(a,b) -> false, context switch; Thread 2 checks isConnected(a,b) -> false; both add connections.
B. Thread 1 and Thread 2 both call addConnection simultaneously, but one fails due to a database constraint.
C. Thread 1 adds connection, then Thread 2 removes it before Thread 1 commits.
D. Thread 1 and Thread 2 both read connection list after addition, causing stale cache.

Solution

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

    Without synchronization, both threads can see no existing connection and proceed to add, causing duplicates.
  2. Step 2: Trace exact thread interleaving

    Thread 1 calls isConnected(a,b) and gets false, then context switches before adding. Thread 2 also calls isConnected(a,b) and gets false, then both add connections concurrently.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Check-then-act gap causes double connection addition [check]
Hint: Check-then-act without sync -> double add race [check]
Common Mistakes:
5. In a parking lot system, the parkVehicle() method checks if a spot is available and then marks it occupied. Without synchronized, what exact thread interleaving causes double-booking?
medium
A. Thread 1 parks vehicle, Thread 2 waits until Thread 1 finishes, then parks.
B. Thread 1 checks spot availability -> true, context switch; Thread 2 checks availability -> true; both mark spot occupied.
C. Thread 1 marks spot occupied, Thread 2 checks availability -> false, no double-booking.
D. Thread 1 and Thread 2 both crash simultaneously causing no booking.

Solution

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

    Without synchronization, Thread 1 reads spot as available but before marking occupied, context switches to Thread 2 which also reads available.
  2. Step 2: Both threads proceed to mark the spot occupied independently

    This leads to double-booking as both think the spot was free at check time.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Check-then-act gap -> both threads see available -> double-booking [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