Lesson 7 / 25

Design a Parking Lot

Floors, spots, tickets and pricing.

Requirements and model

Clarify: multiple floors; spot sizes (small, compact, large); vehicles (motorcycle, car, truck) that fit certain sizes; entry issues a ticket, exit computes a fee and frees the spot; display free counts. Model: ParkingLot has Floors, each with ParkingSpots; Vehicle has a VehicleType; Ticket records vehicle, spot and entry time. Put spot selection in a SpotAllocationStrategy (nearest first, by floor) and fees in a PricingStrategy. Concurrency: two entry gates must not assign the same spot, so allocation must be atomic, for example by synchronising on the floor or using a concurrent free-spot queue per size.

Classic object-oriented designs

Parking lots, elevators and vending machines appear in many LLD rounds because they test modelling, strategy and state.

Three problems: a parking lot, an elevator system and a vending machine as a state machine.
Figure 3.1 — Parking lot, elevator and vending machine models.

Core classes

Java sketch; getters and validation trimmed.

enum SpotSize { SMALL, COMPACT, LARGE }
enum VehicleType { MOTORCYCLE, CAR, TRUCK }

record Vehicle(String plate, VehicleType type) {}
record Ticket(String id, Vehicle vehicle, ParkingSpot spot, java.time.Instant entryTime) {}

class ParkingSpot {
    final String id; final SpotSize size;
    ParkingSpot(String id, SpotSize size) { this.id = id; this.size = size; }
}

class Floor {
    private final java.util.Map<SpotSize, java.util.Deque<ParkingSpot>> free = new java.util.EnumMap<>(SpotSize.class);

    synchronized java.util.Optional<ParkingSpot> take(SpotSize size) {
        java.util.Deque<ParkingSpot> q = free.get(size);
        return (q == null || q.isEmpty()) ? java.util.Optional.empty() : java.util.Optional.of(q.poll());
    }
    synchronized void release(ParkingSpot spot) {
        free.computeIfAbsent(spot.size, s -> new java.util.ArrayDeque<>()).push(spot);
    }
}

interface SpotAllocationStrategy {
    java.util.Optional<ParkingSpot> allocate(java.util.List<Floor> floors, VehicleType type);
}

Map vehicle to allowed sizes

A small table such as CAR -> [COMPACT, LARGE] keeps fitting rules in one place and makes adding a new vehicle type a data change.

Quick check: Why make spot allocation atomic?

  • So two gates cannot assign the same spot at the same time
  • To speed up fee calculation
  • To avoid needing tickets
  • Because enums are not thread safe
Answer

So two gates cannot assign the same spot at the same time — Concurrent entries race for spots.