Skip to content
System design course
Ch.4 · Designing real systems·concept ·8 min read

Designing a parking garage

A classic object-oriented design warm-up — model the entities, relationships, and rules of a multi-level parking lot before writing a line of code.


Why start here

Parking garage (and vending machine, next) are object-oriented design problems, not distributed-systems problems. They test whether you can take messy real-world rules and turn them into clean classes, relationships, and behaviors — the foundation under every larger system. No QPS math here; the skill is modeling.

Step 1 — Requirements

Functional:

  • A garage has multiple levels, each with many spots.
  • Spots come in types (motorcycle, compact, large/handicapped) and a vehicle fits certain types.
  • A vehicle enters, is assigned a spot, gets a ticket; on exit it pays based on duration.
  • Track availability (which spots are free) and show a full/space display.

Non-functional: correct spot assignment, support concurrent entries/exits (thread-safe), and be extensible — new vehicle types, new pricing, new spot types shouldn’t require rewrites.

Out of scope (state it): reservations, payments integration internals, multi-garage. Keep it one garage.

Step 2 — Identify the entities (the nouns)

Pull the core objects straight from the requirements:

  • ParkingLot — the top-level system (often a singleton); holds levels.
  • Level (ParkingFloor) — holds spots; tracks free spots per type.
  • ParkingSpot — a single space, has a type and an occupied flag.
  • Vehicle (abstract) → Motorcycle, Car, Truck/Bus — knows which spot types it can use.
  • Ticket — issued on entry; records the spot, vehicle, and entry time.
  • EntrancePanel / ExitPanel — issue tickets and process payment.
  • ParkingRate / PricingStrategy — computes the fee from duration.

Step 3 — Relationships and the class sketch

ParkingLot 1──* Level 1──* ParkingSpot
Vehicle ──assigned──▶ ParkingSpot (via Ticket)
ExitPanel ──uses──▶ PricingStrategy ──reads──▶ Ticket

Use enums for fixed sets — VehicleType, SpotType, PaymentStatus — rather than strings, so the compiler enforces validity.

Step 4 — The behaviors (the verbs)

  • parkVehicle(vehicle) → find a compatible free spot, occupy it, issue a ticket.
  • unparkVehicle(ticket) → free the spot, compute the fee, take payment.
  • findSpot(vehicle) → the allocation policy (nearest level? first-fit by type?).
  • isFull() / availability counts per type.

Step 5 — Design patterns worth naming

This is where you score OOD points. Match a pattern to a requirement:

  • StrategyPricingStrategy and SpotAllocationStrategy as pluggable policies, so pricing/allocation rules change without touching the lot. (Directly serves the extensibility requirement.)
  • Factory — a VehicleFactory/SpotFactory to create the right subtype.
  • Singleton — one ParkingLot instance.
  • Observer — the availability display subscribes to spot occupied/freed events and updates live.
  • State — a spot or ticket moving through states (free → occupied → paid).

The interview cue

Lead with the entities and their relationships, use enums for types, and call out Strategy for pricing/allocation as your extensibility story. Then say “let me implement the core classes and the allocation algorithm” — which is exactly the next lesson. Modeling cleanly and naming one or two patterns with the requirement they satisfy is the whole game in an OOD round.