Difficulty: Tier 1 (LLD) Asked at: Tkxel, Systems Ltd, Arbisoft, Amazon, most product companies Time budget: 45 min
A change of pace: this is a low-level design (LLD) question — no servers, no scale, no databases. It’s about classes: their responsibilities, relationships, and whether your design extends cleanly when the interviewer adds “now support electric vehicles” at minute 35. The parking lot is the canonical LLD problem; master its shape and elevator, vending machine, and the rest pattern-match.
Prerequisites: Low-Level Design Round, Layered & Hexagonal
Functional:
Constraints to clarify: payment methods? multiple entry/exit gates? handicapped/EV/reserved spots? pricing model (hourly/flat)? Scope it, then design.
ParkingLot, ParkingFloor, ParkingSpot, Vehicle, Ticket, Payment, EntryGate, ExitGate, ParkingRate
🚨 Nouns in the problem become classes — a reliable heuristic for finding entities.
ParkingLot has-many ParkingFloor
ParkingFloor has-many ParkingSpot
Vehicle is-a Motorcycle | Car | Truck (inheritance)
ParkingSpot is-a SmallSpot | MediumSpot | LargeSpot
Ticket associates a Vehicle with a ParkingSpot + entry time
Payment settles a Ticket
ParkingRate (Strategy) computes fee from duration/type
enum VehicleType { MOTORCYCLE, CAR, TRUCK }
enum SpotType { SMALL, MEDIUM, LARGE }
abstract class Vehicle {
String licensePlate
VehicleType type
}
class Car extends Vehicle { type = CAR }
class Motorcycle extends Vehicle { type = MOTORCYCLE }
class Truck extends Vehicle { type = TRUCK }
abstract class ParkingSpot {
String id
SpotType type
boolean isAvailable
Vehicle currentVehicle
abstract boolean canFit(Vehicle v) // size compatibility
void assign(Vehicle v)
void remove()
}
class SmallSpot extends ParkingSpot { canFit → v.type == MOTORCYCLE }
class MediumSpot extends ParkingSpot { canFit → v.type in (MOTORCYCLE, CAR) }
class LargeSpot extends ParkingSpot { canFit → any type }
class Ticket {
String id
Vehicle vehicle
ParkingSpot spot
DateTime entryTime, exitTime
}
interface PricingStrategy { double calculate(Ticket t) } // Strategy pattern
class HourlyPricing implements PricingStrategy { ... }
class FlatPricing implements PricingStrategy { ... }
class ParkingFloor {
List<ParkingSpot> spots
ParkingSpot findAvailableSpot(Vehicle v) // first spot where canFit && isAvailable
}
class ParkingLot { // orchestrator (often a Singleton)
List<ParkingFloor> floors
PricingStrategy pricing
Ticket parkVehicle(Vehicle v) // find spot across floors, assign, issue ticket
Payment unpark(Ticket t) // free spot, compute fee, take payment
}
🚨 Apply patterns because they fit, not to show off.
| Pattern | Where | Why |
|---|---|---|
| Strategy | PricingStrategy |
Swap pricing (hourly/flat/type-based) without touching ParkingLot → open/closed |
| Factory | Creating Vehicle/ParkingSpot by type |
Centralize construction |
| Singleton | ParkingLot instance |
One lot object (use judiciously) |
| Observer | Notify a display board / waiting driver when a spot frees | Decouple notification |
🚨 The interviewer will add a requirement at minute 35. Your design passes if it absorbs it by adding code, not editing existing code (open/closed).
ElectricSpot (or better, compose a
ChargingCapability onto a spot) and, if needed, an EV pricing strategy. No existing class changes.
✅PricingStrategy implementation, injected. ✅findAvailableSpot. ✅If adding EV spots forces you to edit a giant if (type == ...) switch, your design failed the test — that’s
why polymorphism over conditionals matters here.
Two cars racing for the last spot: assign() must be atomic (lock the spot or use an atomic
compare-and-set on isAvailable) so only one succeeds. Multiple gates → the ParkingLot must be
thread-safe. Mentioning this shows real-world awareness even in an LLD round.
| Choice | Good design | Weak design |
|---|---|---|
| Vehicle/spot types | Polymorphism (subclasses / canFit) |
if/switch on an enum everywhere |
| Pricing | Strategy interface (swappable) | Hardcoded in unpark() |
| Extensibility | Add EV spot = new class | Add EV spot = edit existing classes |
| Spot capabilities | Composition where combinatorial | Deep inheritance explosion |
| Encapsulation | Spot manages its own state | External code flips flags directly |
ChargingCapability rather than an
exploding subtype hierarchy), names concurrency on spot assignment, questions the Singleton, makes
spot-selection pluggable, and explicitly ties every choice to open/closed and the extension test.