Low-Level Design: Parking Lot System
The parking lot LLD is one of the most common interview questions at companies like Amazon, Google, and Microsoft. It tests state management, hierarchy modeling, and object-oriented design.
Requirements
- Multiple floors, each with multiple spots
- Different vehicle types: Motorcycle, Car, Truck
- Different spot types: Compact, Regular, Large
- A motorcycle fits in any spot; a car fits in compact or regular; a truck only in large
- Ticket generation on entry, fee calculation on exit
- Find available spot efficiently
- Support for reserved/handicapped spots
Core Class Design
Enums and Vehicle Hierarchy
from enum import Enum
from datetime import datetime
from abc import ABC, abstractmethod
class VehicleType(Enum):
MOTORCYCLE = "motorcycle"
CAR = "car"
TRUCK = "truck"
class SpotType(Enum):
COMPACT = "compact"
REGULAR = "regular"
LARGE = "large"
class SpotStatus(Enum):
AVAILABLE = "available"
OCCUPIED = "occupied"
RESERVED = "reserved"
class Vehicle(ABC):
def __init__(self, license_plate: str, vehicle_type: VehicleType):
self.license_plate = license_plate
self.vehicle_type = vehicle_type
@abstractmethod
def can_fit_in(self, spot_type: SpotType) -> bool:
pass
class Motorcycle(Vehicle):
def __init__(self, license_plate: str):
super().__init__(license_plate, VehicleType.MOTORCYCLE)
def can_fit_in(self, spot_type: SpotType) -> bool:
return True # Motorcycles fit anywhere
class Car(Vehicle):
def __init__(self, license_plate: str):
super().__init__(license_plate, VehicleType.CAR)
def can_fit_in(self, spot_type: SpotType) -> bool:
return spot_type in (SpotType.COMPACT, SpotType.REGULAR, SpotType.LARGE)
class Truck(Vehicle):
def __init__(self, license_plate: str):
super().__init__(license_plate, VehicleType.TRUCK)
def can_fit_in(self, spot_type: SpotType) -> bool:
return spot_type == SpotType.LARGE
Parking Spot and Floor
class ParkingSpot:
def __init__(self, spot_id: str, spot_type: SpotType, floor: int):
self.spot_id = spot_id
self.spot_type = spot_type
self.floor = floor
self.status = SpotStatus.AVAILABLE
self.parked_vehicle: Vehicle = None
def is_available(self) -> bool:
return self.status == SpotStatus.AVAILABLE
def park(self, vehicle: Vehicle):
if not vehicle.can_fit_in(self.spot_type):
raise ValueError(f"Vehicle type {vehicle.vehicle_type} cannot fit in {self.spot_type} spot")
self.parked_vehicle = vehicle
self.status = SpotStatus.OCCUPIED
def free(self):
self.parked_vehicle = None
self.status = SpotStatus.AVAILABLE
def get_hourly_rate(self) -> float:
rates = {SpotType.COMPACT: 2.0, SpotType.REGULAR: 3.0, SpotType.LARGE: 5.0}
return rates[self.spot_type]
class ParkingFloor:
def __init__(self, floor_number: int):
self.floor_number = floor_number
self.spots: dict[str, ParkingSpot] = {}
# Available spots by type for O(1) lookup
self._available: dict[SpotType, set] = {
SpotType.COMPACT: set(),
SpotType.REGULAR: set(),
SpotType.LARGE: set(),
}
def add_spot(self, spot: ParkingSpot):
self.spots[spot.spot_id] = spot
if spot.is_available():
self._available[spot.spot_type].add(spot.spot_id)
def get_available_spot(self, vehicle: Vehicle) -> ParkingSpot:
"""Find first available spot that fits this vehicle."""
# Check spots in order of size preference (smallest that fits)
preference = {
VehicleType.MOTORCYCLE: [SpotType.COMPACT, SpotType.REGULAR, SpotType.LARGE],
VehicleType.CAR: [SpotType.COMPACT, SpotType.REGULAR, SpotType.LARGE],
VehicleType.TRUCK: [SpotType.LARGE],
}
for spot_type in preference[vehicle.vehicle_type]:
if self._available[spot_type]:
spot_id = next(iter(self._available[spot_type]))
return self.spots[spot_id]
return None
def park_vehicle(self, vehicle: Vehicle) -> ParkingSpot:
spot = self.get_available_spot(vehicle)
if not spot:
return None
spot.park(vehicle)
self._available[spot.spot_type].discard(spot.spot_id)
return spot
def free_spot(self, spot_id: str):
spot = self.spots[spot_id]
spot.free()
self._available[spot.spot_type].add(spot_id)
def get_available_count(self) -> dict:
return {stype: len(ids) for stype, ids in self._available.items()}
Ticket and Payment
import uuid
from dataclasses import dataclass, field
@dataclass
class ParkingTicket:
ticket_id: str = field(default_factory=lambda: str(uuid.uuid4())[:8].upper())
vehicle: Vehicle = None
spot: ParkingSpot = None
entry_time: datetime = field(default_factory=datetime.now)
exit_time: datetime = None
amount_paid: float = 0.0
def calculate_fee(self) -> float:
if not self.exit_time:
self.exit_time = datetime.now()
duration_hours = (self.exit_time - self.entry_time).total_seconds() / 3600
# Minimum 1 hour charge
billable_hours = max(1.0, duration_hours)
return round(billable_hours * self.spot.get_hourly_rate(), 2)
class PaymentProcessor:
def process_payment(self, ticket: ParkingTicket, amount: float) -> bool:
# In real system: integrate with payment gateway
ticket.amount_paid = amount
return True
Parking Lot (Main Controller)
import threading
class ParkingLot:
_instance = None
_lock = threading.Lock()
def __new__(cls):
"""Singleton pattern — one parking lot system."""
if not cls._instance:
with cls._lock:
if not cls._instance:
cls._instance = super().__new__(cls)
cls._instance._initialized = False
return cls._instance
def __init__(self):
if self._initialized:
return
self.name = "Main Parking Lot"
self.floors: dict[int, ParkingFloor] = {}
self.active_tickets: dict[str, ParkingTicket] = {} # license_plate -> ticket
self.payment_processor = PaymentProcessor()
self._lock = threading.Lock()
self._initialized = True
def add_floor(self, floor: ParkingFloor):
self.floors[floor.floor_number] = floor
def park_vehicle(self, vehicle: Vehicle) -> ParkingTicket:
with self._lock:
if vehicle.license_plate in self.active_tickets:
raise ValueError(f"Vehicle {vehicle.license_plate} already parked")
# Find spot across all floors (prefer lower floors)
for floor_num in sorted(self.floors.keys()):
floor = self.floors[floor_num]
spot = floor.park_vehicle(vehicle)
if spot:
ticket = ParkingTicket(vehicle=vehicle, spot=spot)
self.active_tickets[vehicle.license_plate] = ticket
return ticket
raise ValueError("Parking lot is full")
def exit_vehicle(self, license_plate: str) -> ParkingTicket:
with self._lock:
if license_plate not in self.active_tickets:
raise ValueError(f"No active ticket for {license_plate}")
ticket = self.active_tickets.pop(license_plate)
ticket.exit_time = datetime.now()
fee = ticket.calculate_fee()
self.payment_processor.process_payment(ticket, fee)
# Free the spot
floor = self.floors[ticket.spot.floor]
floor.free_spot(ticket.spot.spot_id)
return ticket
def get_availability(self) -> dict:
result = {}
for floor_num, floor in self.floors.items():
result[f"Floor {floor_num}"] = floor.get_available_count()
return result
Key Design Decisions
- Singleton ParkingLot: One system-wide controller; thread-safe double-checked locking
- Available spot sets per type: O(1) availability check and spot retrieval instead of O(n) scan
- Strategy for vehicle-spot compatibility:
can_fit_in()on Vehicle, not on Spot — follows Tell Don’t Ask - Thread safety: Lock on park/exit operations to prevent double-parking races
- Preference ordering: Cars prefer compact > regular > large to preserve large spots for trucks
Extension Points
- Electric vehicle charging: Add
SpotType.EV_CHARGING; EVVehicle prefers EV spots - Reservations: Reserve spots ahead of time; hold with timeout using scheduled job
- Dynamic pricing: Peak hours command higher rates; inject pricing strategy into PaymentProcessor
- Display boards: Observer pattern — floors publish availability changes; display boards subscribe
- License plate recognition: Replace manual entry with camera API; auto-create Vehicle objects
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”How do you design a Parking Lot system in an OOP interview?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Start with an abstract Vehicle hierarchy (Motorcycle, Car, Truck) where each implements can_fit_in(SpotType). A ParkingFloor manages spots using per-type sets for O(1) availability lookup. The ParkingLot singleton coordinates floors, issues ParkingTickets on entry, frees spots on exit, and uses a thread lock to prevent race conditions when multiple vehicles enter simultaneously.”}},{“@type”:”Question”,”name”:”How do you handle different vehicle types and spot sizes in a Parking Lot design?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Define SpotType enum (Compact, Regular, Large) and VehicleType enum. Each Vehicle subclass implements can_fit_in() — motorcycles fit anywhere, cars fit compact/regular/large, trucks only large. When finding a spot, prefer the smallest available spot that fits the vehicle to preserve larger spots for bigger vehicles. This avoids wasting large spots on motorcycles.”}},{“@type”:”Question”,”name”:”How do you calculate parking fees in a Parking Lot system?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”A ParkingTicket records entry_time at creation and exit_time when the vehicle leaves. Fee = max(1 hour minimum, actual duration in hours) × hourly rate for that spot type. Different spot types command different rates: compact is cheapest, large spots are most expensive. The PaymentProcessor abstracts the actual payment method (credit card, app, cash).”}},{“@type”:”Question”,”name”:”Why use the Singleton pattern for the Parking Lot controller?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”The parking lot represents a single physical system with shared state — spot availability, active tickets. A Singleton ensures all requests go through one controller, preventing inconsistencies like the same spot being assigned to two vehicles. Thread safety requires a lock around park/exit operations. Double-checked locking in __new__ ensures thread-safe lazy initialization without locking on every access.”}}]}
🏢 Asked at: Uber Interview Guide 2026: Dispatch Systems, Geospatial Algorithms, and Marketplace Engineering
🏢 Asked at: Lyft Interview Guide 2026: Rideshare Engineering, Real-Time Dispatch, and Safety Systems
🏢 Asked at: Atlassian Interview Guide
🏢 Asked at: Meta Interview Guide 2026: Facebook, Instagram, WhatsApp Engineering
🏢 Asked at: Apple Interview Guide 2026: iOS Systems, Hardware-Software Integration, and iCloud Architecture
🏢 Asked at: Snap Interview Guide
🏢 Asked at: Airbnb Interview Guide 2026: Search Systems, Trust and Safety, and Full-Stack Engineering
🏢 Asked at: DoorDash Interview Guide
Asked at: Shopify Interview Guide