Why this matters
- One of the most common LLD prompts — patterns for allocation, ticketing, and pricing appear everywhere.
- Tests OOP, Strategy, and facade coordination in a single story.
- CampusOS parking is the reference machine problem for the rest of the track.
ParkingLotentry facade
ParkingFloorcollection of spots
Ticketissued on entry
Vehiclecar, bike, truck
ParkingSpot links Vehicle when occupied; Strategy picks spot by vehicle type.
Requirements
Functional
- Multiple spot types: handicapped, compact, large, motorcycle
- Vehicle types: car, truck, van, motorcycle — each maps to compatible spots
- Entry issues a ticket; exit calculates hourly fee and frees the spot
- Display board shows availability per spot type; show "FULL" when capacity reached
- Multiple entry and exit gates share one lot
Non-functional
- In-process, single JVM for this article
- Spot assignment must be consistent under concurrent entry at two gates
- Pricing rule should be replaceable (Strategy) without editing
ParkingLot
Core classes
| Class | Responsibility |
|---|---|
| ParkingLot | Facade — park, exit, availability |
| ParkingFloor | Owns a collection of spots |
| ParkingSpot | Type, occupied flag, park/vacate |
| Vehicle | Type enum + identifier |
| ParkingTicket | Entry time, spot reference, fee calculation |
| SpotAssignmentStrategy | Picks next free compatible spot |
| DisplayBoard | Publishes availability snapshot |
ParkingLot
ResponsibilityFacade — park, exit, availabilityParkingFloor
ResponsibilityOwns a collection of spotsParkingSpot
ResponsibilityType, occupied flag, park/vacateVehicle
ResponsibilityType enum + identifierParkingTicket
ResponsibilityEntry time, spot reference, fee calculationSpotAssignmentStrategy
ResponsibilityPicks next free compatible spotDisplayBoard
ResponsibilityPublishes availability snapshot
Entry and exit flow
- Entry — vehicle arrives → strategy finds spot → spot.occupy() → ticket issued with timestamp
- Exit — ticket presented → fee = hours × rate → payment → spot.vacate() → board updated
public enum VehicleType { CAR, TRUCK, VAN, MOTORCYCLE }
public enum SpotType { HANDICAPPED, COMPACT, LARGE, MOTORCYCLE }
public final class ParkingSpot {
private final SpotType type;
private boolean occupied;
public boolean canFit(VehicleType vehicle) {
return compatibility.get(vehicle).contains(type);
}
public void park() {
if (occupied) throw new IllegalStateException("Spot already taken");
occupied = true;
}
public void vacate() { occupied = false; }
}
public final class ParkingLot {
private final List<ParkingFloor> floors;
private final SpotAssignmentStrategy strategy;
private final DisplayBoard board;
public Optional<ParkingTicket> park(Vehicle vehicle) {
return strategy.findSpot(floors, vehicle)
.map(spot -> {
spot.park();
var ticket = new ParkingTicket(vehicle, spot, Instant.now());
board.refresh(countAvailability());
return ticket;
});
}
}
Extensions
- Electric charging spots — new
SpotType+ compatibility row - Dynamic pricing — swap
PricingStrategyat exit - Multi-lot campus — one
ParkingLotper physical lot behind a registry
Quick recall
Everything you need if you only revisit this box.
- ParkingLot is the facade; floors own spots
- Strategy selects compatible free spot
- Ticket binds vehicle, spot, entry time
- DisplayBoard observes availability changes
- Payment and pricing are separate collaborators
CampusOS extension
At campus scale, ticket and payment events flow to a central billing service; availability may be cached at each gate. See System Design articles on caching and idempotent payments when you outgrow one JVM.
Test yourself
Answer these before moving on — recall is what makes it stick.