The Parking Lot system is one of the most frequently asked Low Level Design problems in software engineering interviews. Companies like Amazon, Flipkart, Microsoft, and Uber use this problem to evaluate your understanding of Object-Oriented Design, SOLID principles, and the Strategy design pattern. In this complete parking lot LLD guide, we go from requirements to class diagram to working Java code.
Why Interviewers Ask the Parking Lot LLD Problem
The Parking Lot problem is deceptively simple on the surface but reveals a lot about how you think. Interviewers want to see:
- Can you identify the right entities without over-engineering?
- Do you apply Single Responsibility Principle — each class does one thing?
- Can you use the Strategy pattern for extensible pricing?
- Do you think about edge cases like concurrent access and finding the nearest slot?
- Can you model enums cleanly for vehicle types and slot sizes?
Functional Requirements
- Support multiple floors, each with a configurable number of slots
- Three vehicle types: Bike, Car, Truck — each requires a different slot size
- Allocate the nearest available slot to an incoming vehicle
- Issue a ticket on entry with timestamp and slot details
- Calculate parking fee on exit based on duration and vehicle type
- Free up the slot when a vehicle exits
- Display available slot count per floor and vehicle type
Non-Functional Requirements
- Concurrent entry and exit must be handled safely — no double-allocation of slots
- Adding a new vehicle type or pricing strategy must not require modifying existing classes (OCP)
- Slot search should be O(1) or O(floors) using data structures, not a full O(n) scan
Core Entities — Parking Lot LLD Class Design
- ParkingLot — singleton, manages all floors, entry and exit
- Floor — contains slots, tracks availability per slot type
- Slot — type (SMALL/MEDIUM/LARGE), number, floor, occupied status
- Vehicle — abstract base; Bike, Car, Truck extend it
- Ticket — issued at entry: vehicle, slot, entry time
- PricingStrategy — interface; HourlyPricing, FlatRatePricing implement it
- Payment — amount, method, timestamp
- EntrancePanel / ExitPanel — hardware interface abstractions
Text-Based Class Diagram
ParkingLot (Singleton) +-- floors: List<Floor> +-- pricingStrategy: PricingStrategy +-- activeTickets: Map<String, Ticket> +-- parkVehicle(vehicle): Ticket +-- unparkVehicle(ticketId): Payment Floor +-- floorNumber: int +-- slots: List<Slot> +-- getNearestAvailableSlot(type): Slot Slot +-- slotNumber: int +-- type: SlotType (SMALL / MEDIUM / LARGE) +-- isOccupied: boolean +-- assignVehicle() / free() Vehicle (abstract) +-- licensePlate: String +-- type: VehicleType Bike / Car / Truck extend Vehicle Ticket +-- ticketId: String +-- vehicle: Vehicle +-- slot: Slot +-- entryTime: LocalDateTime PricingStrategy (interface) +-- calculateFee(ticket, exitTime): double HourlyPricing implements PricingStrategy FlatRatePricing implements PricingStrategy
Strategy Pattern for Pricing — Java
public interface PricingStrategy {
double calculateFee(Ticket ticket, LocalDateTime exitTime);
}
public class HourlyPricing implements PricingStrategy {
private final Map<VehicleType, Double> ratePerHour = new EnumMap<>(VehicleType.class);
public HourlyPricing() {
ratePerHour.put(VehicleType.BIKE, 10.0);
ratePerHour.put(VehicleType.CAR, 20.0);
ratePerHour.put(VehicleType.TRUCK, 50.0);
}
@Override
public double calculateFee(Ticket ticket, LocalDateTime exitTime) {
long hours = ChronoUnit.HOURS.between(ticket.getEntryTime(), exitTime);
hours = Math.max(hours, 1); // minimum 1 hour
return hours * ratePerHour.get(ticket.getVehicle().getType());
}
}ParkingLot Core Logic
public class ParkingLot {
private static ParkingLot instance;
private final List<Floor> floors;
private final PricingStrategy pricingStrategy;
private final Map<String, Ticket> activeTickets = new ConcurrentHashMap<>();
private ParkingLot(List<Floor> floors, PricingStrategy strategy) {
this.floors = floors;
this.pricingStrategy = strategy;
}
public static synchronized ParkingLot getInstance(List<Floor> floors, PricingStrategy strategy) {
if (instance == null) instance = new ParkingLot(floors, strategy);
return instance;
}
public Ticket parkVehicle(Vehicle vehicle) {
SlotType required = SlotType.forVehicle(vehicle.getType());
for (Floor floor : floors) {
Slot slot = floor.getNearestAvailableSlot(required);
if (slot != null) {
slot.assignVehicle(vehicle);
Ticket ticket = new Ticket(UUID.randomUUID().toString(),
vehicle, slot, LocalDateTime.now());
activeTickets.put(ticket.getTicketId(), ticket);
return ticket;
}
}
throw new ParkingFullException("No slot available for " + vehicle.getType());
}
public Payment unparkVehicle(String ticketId) {
Ticket ticket = activeTickets.remove(ticketId);
if (ticket == null) throw new InvalidTicketException(ticketId);
LocalDateTime exitTime = LocalDateTime.now();
double fee = pricingStrategy.calculateFee(ticket, exitTime);
ticket.getSlot().free();
return new Payment(fee, PaymentMethod.CASH, exitTime);
}
}Key Design Decisions
- Singleton ParkingLot: Only one instance should exist per system. Use double-checked locking or an enum-based singleton for thread safety in a multi-threaded environment.
- Strategy over inheritance for pricing: Subclassing ParkingLot per pricing model violates SRP. With Strategy, adding a weekend rate or EV discount is a new class — zero changes to existing code.
- ConcurrentHashMap for active tickets: Multiple entry and exit lanes run in parallel. ConcurrentHashMap provides thread-safe put/remove without a global lock.
- SlotType maps to VehicleType: Bike → SMALL, Car → MEDIUM, Truck → LARGE. Keep this mapping in one place — a static factory method on SlotType — not scattered across callers.
Common Follow-Up Questions
- "How do you handle two vehicles racing for the same slot?" — Synchronize
getNearestAvailableSlot + assignVehicleat the floor level, or use an atomic CAS operation on the slot's occupied flag. - "How do you support EV charging slots?" — Add a
SlotFeatureenum (REGULAR, EV_CHARGING, HANDICAP). Slot gets a feature field. Search filters by feature when needed. - "How do you find the nearest slot efficiently?" — Each floor maintains a sorted set or min-heap of available slot numbers per type. getNearestAvailableSlot is O(log n).
- "How would you add monthly subscription support?" — Vehicle gets an optional Subscription. PricingStrategy checks for an active subscription before calculating the hourly fee.
FAQ — Parking Lot Low Level Design
What design patterns are used in Parking Lot LLD?
The primary patterns are Strategy (swap pricing algorithms without changing ParkingLot),Singleton (one ParkingLot instance), and Factory (create Vehicle objects from a type string). The Observer pattern is optionally used to update a display board when slot availability changes.
What is the class diagram for a Parking Lot system?
Core classes: ParkingLot (singleton) → Floor → Slot, Vehicle (abstract) → Bike/Car/Truck, Ticket (links Vehicle + Slot + entry time), PricingStrategy → HourlyPricing/FlatRatePricing, Payment. ParkingLot has many Floors; each Floor has many Slots.
How do you handle concurrent parking in Parking Lot LLD?
Use ConcurrentHashMap for active tickets and synchronize slot assignment at the floor level. Alternatively, use an atomic boolean in Slot with compareAndSet so only one thread can mark a slot occupied at a time.
Is the Parking Lot problem easy or hard?
Beginner to intermediate. Entities are clear, the Strategy pattern is textbook, and the concurrency requirement adds depth. It is the best first LLD problem because it covers fundamentals — entities, relationships, a design pattern, and edge cases — without overwhelming complexity.