Parking Lot
A classic machine-coding prompt: design the classes behind a parking lot that assigns spots to vehicles and charges a fee on the way out. The interesting decisions are not the happy path - they're what you split into its own class, and why.
Requirements
Functional
- A vehicle enters, is assigned an available spot, and receives a ticket.
- A vehicle exits by presenting its ticket; the spot is freed and a fee is charged for the time parked.
- The lot has multiple floors, each with a fixed number of spots.
- Spots come in different sizes (motorcycle, compact, large) and a vehicle can only park in a spot at least as large as itself.
Non-functional
- Spot lookup should scale with lot size - no linear scan of every spot on every request once the lot has thousands of them (a real answer buckets spots by floor and size; this page keeps the lookup simple and calls out the upgrade in the design decisions below).
- The fee formula changes often (flat rate today, size-based or time-of-day pricing
tomorrow) and should never require touching
ParkingLot.
Design
ParkingLot is the entry point but owns almost no logic itself - it delegates spot lookup
to ParkingFloor, delegates fee math to a pluggable FeeStrategy, and only coordinates the
two. That split is the whole design: every class answers exactly one question.
- 1A vehicle arrives at the entry gate; the gate only knows the lot, never a spot.
- 2The lot asks each floor in turn - it never looks at a spot directly.
- 3The floor is the only class that walks its own spot list.
- 4Once a spot is found, the lot marks it occupied.
- 5A ticket is minted to carry the spot and entry time back to the caller.
- 6Later, the exit gate presents the ticket - not the vehicle or the spot.
- 7The spot is freed first, independent of how the fee is computed.
- 8Pricing is asked for a number, not consulted about the flow. Swap it and nothing else here changes.
Ticket is the one object that outlives a single method call - it is handed to the caller
at entry and handed back at exit, and it is the only thing that has to carry both the spot
and the entry time across that gap.
Class diagram
implementsusescreates
Code
Design decisions
- Spots split by size instead of one generic
ParkingSpot. A single spot type with asizefield (rather than aCompactSpot/LargeSpotclass hierarchy) keepsfindAvailableSpota single comparison instead of a type check. The size differences here are data, not behavior, so a class hierarchy would be one class per enum value for no extra polymorphism gained. - Fee calculation is pulled into its own
FeeStrategyinterface. Pricing is the part of a parking lot that actually changes in the real world - promotions, size-based rates, time-of-day surcharges. Isolating it behind one method meansParkingLotnever changes when pricing does; that's the Strategy pattern earning its keep rather than being applied for its own sake. ParkingFloorowns its spots,ParkingLotowns its floors - composition all the way down. Nothing outside the lot ever holds a spot reference directly; every access goes throughparkVehicle/unparkVehicle, so the invariant "a spot's occupant matches some active ticket" can only be broken inside this file.- What's missing for a real system:
findAvailableSpot's linear scan needs an index (e.g. a free-list per floor per size) once a lot has more than a few hundred spots, and two attendants assigning the same spot at once needs the assignment step to be atomic (a lock per spot, or a compare-and-swap on its state) - neither is in scope for a 45-minute whiteboard version, but naming them is what separates a design that merely compiles from one that would survive contact with concurrency.