Object-Oriented Design Interview

Course Content

Object-Oriented Design Interview

14 sections · 29 lessons

Parking Lot: requirements and the class model


This is the first of eleven worked problems, and the one every other problem in the course is measured against. This lesson covers the first twenty-five minutes of the round — the prompt, the questions that change the model, the requirements written on the board, and the class model drawn from them — before any real code is written.

Four questions worth asking, two that are notThese change the model• Do spot sizesconstrain which vehicle fits?• Is pricing flat, hourly, or variable?• One lot, or a chain of them?• Is payment inside the scope?These change nothing• How many cars per day?• Which database should I use?• Which language do you prefer?• Is there a mobile app?
A clarifying question earns points only when a different answer would redraw a class.

Why this problem is the canonical first one

It has every ingredient of the round and no domain knowledge barrier. Everyone understands parking. It has entities with obvious names, a hierarchy that is genuinely useful, a rule (pricing) that clearly wants to be swappable, a lookup that must not be a linear scan, and a concurrency question that writes itself. Interviewers use it because a weak candidate and a strong candidate produce visibly different answers within fifteen minutes.

This section runs at the slowest pace in the course, because it is teaching the framework from Section 2 as well as the design.

The four questions that change the model

1. "One level or multiple floors?" A single-level lot is ParkingLot → ParkingSpot. Multiple floors add a Floor class, per-floor availability counts, and a display board per floor. Assume multiple floors unless told otherwise — it is the more interesting design and interviewers usually want it.

2. "Are there different vehicle and spot sizes?" This is the question that produces the hierarchy. If yes, you need spot sizes, vehicle sizes, and a rule for which vehicle fits which spot — including whether a car may take a large spot when no medium ones are free. Assume yes, with three sizes.

3. "How is the fee computed?" The answer decides whether pricing is a field, a method, or an interface. Ask specifically: "Is it a flat rate, hourly, or does it vary by vehicle type and time of day?" Anything past "flat" justifies a Strategy (The seven patterns that actually appear).

4. "Is payment in scope, and how many entry and exit gates are there?" Payment is usually out of scope as an implementation and in scope as an interface. The gate count is the concurrency question in disguise: four entry gates means four threads competing for the last free spot.

The two questions not worth asking

"Should I handle a million lots?" — no. This is a low-level design round; scaling out to many lots is a distributed system design question and the interviewer will say so.

"What database should I use?" — no. Say "I'll assume a repository interface for persistence" and move on (Phase 5: coding the core, and what to skip).

The assumptions this lesson makes

Written down, because you should write yours down too:

  • One lot, three to five floors, roughly 100 spots per floor.
  • Three spot sizes: small (motorcycles), medium (cars), large (trucks and vans).
  • A vehicle may use its own size or any larger spot.
  • Hourly pricing, varying by spot size, with a flat rate for the first thirty minutes.
  • Four entry gates and four exit gates on one machine, so threads compete but processes do not.
  • Payment is an interface; card processing is out of scope.

Requirements

Five minutes, on the board, in three lists. The third list — what you are not building — is the one that saves you at minute thirty-five.

Three lists and one numberScale: 2,000 spotsCut:gateways, ANPR, appN-F: O(1)spot lookupFunctional:park, paytopbottomThe cut list is written on the board, not merely thought.
The scale number is the only one that changes a decision: 2,000 spots forbids a linear scan.

Functional requirements

Text
1. Park a vehicle: find a free spot of a fitting size, issue a ticket2. Unpark: look up the ticket, compute the fee, free the spot3. Query availability: free spots per floor, per size4. Compute a fee from entry time, exit time, and spot size5. Accept payment and release the exit gate

Five verbs. Each becomes a method on exactly one class by the end of finding the objects, below.

Non-functional requirements

These are where the design becomes interesting, and there are only two that matter.

N1. Finding a free spot must not scan every spot. A 500-spot lot scanned on every entry is 500 checks per car. At four gates and a car every twenty seconds that is manageable, and it is still the wrong answer, because the interviewer is checking whether you notice. The fix — an availability index per floor per size — costs one field and turns the lookup into a constant-time operation.

N2. The same spot must never be assigned to two vehicles. Four entry gates are four threads. Two of them reaching the last medium spot at the same moment is the failure this problem always ends on, and the section's extensions handle it properly.

A third, worth stating because it drives Patterns applied:

N3. Adding a new pricing rule must not modify existing pricing code.

What is explicitly out of scope

Text
CUT (named, not forgotten)- Reservations and pre-booking- Multiple lots / a chain of car parks- Card and wallet payment processing (interface only)- Number-plate recognition, cameras, hardware protocols- Valet parking, staff scheduling, monthly billing runs

Say this list out loud as you write it: "I'm going to leave reservations out — it changes the allocation model significantly and I'd rather get the core flow right first. If we have time at the end I'll come back to it."

Rough scale, because it changes one decision

Interviewers like a number here. A large city lot is 500 to 2,000 spots. Entries during a morning peak might be a few per minute across four gates. Those numbers tell you two things:

  • Everything fits in memory. Maps and lists are fine; you do not need a database for the design to work.
  • Contention is real but low — a handful of concurrent operations, not thousands. That points at simple locking rather than an elaborate lock-free structure, which matters in the section's extensions.

Finding the objects

Ten minutes in words before anything is drawn. Extract the nouns, filter them, then state each survivor's job in one sentence.

What the lot owns, and what it does notParkingLotLevelParkingSpotTicketVehiclePricingStrategy
Vehicle subclasses are honest only while size is the only thing that varies between them.

The candidate nouns

From the requirements: parking lot, floor, spot, vehicle, ticket, fee, payment, gate, size, availability, entry time, display board.

Filtering them

Applying the three filters from Phase 3: finding classes — does it hold state, does it have behaviour, does it change independently:

CandidateVerdictReason
ParkingLotClassHolds floors, coordinates park and unpark
FloorClassHolds spots and its own availability counts
ParkingSpotClassHas state (occupied or not) and behaviour (assign, release)
VehicleClass, abstractState (plate) and one behaviour that varies (its size)
TicketClassThe record of one parking session, from entry to payment
SizeEnumA closed set of values with no behaviour of its own
FeeValueA computed Money on the ticket, not a class
PricingStrategyInterfaceA rule that changes independently — Patterns applied
PaymentInterfaceOut of scope as implementation, in scope as a boundary
GateClass, thinEntry and exit points; useful because they are the concurrency actors
DisplayBoardCutA view over floor availability; adds nothing to the model
AvailabilityNot a classA structure inside Floor — see Spot assignment, in code

Twelve nouns became seven classes, one enum, and two interfaces. Narrate the rejections: "Fee I'm not making a class — it's a computed value with no identity. DisplayBoard I'm cutting; it reads from floor availability and doesn't change the model."

One sentence per class

The one-sentence test from Phase 4: assigning responsibilities. If it needs an "and", the class is wrong.

Text
ParkingLot     — coordinates parking and unparking across its floors.Floor          — holds the spots on one level and knows which are free, by size.ParkingSpot    — represents one physical space and whether a vehicle occupies it.Vehicle        — identifies one vehicle and the smallest spot size it fits in.Ticket         — records one parking session: spot, vehicle, entry time, and payment state.PricingStrategy— turns a ticket into an amount owed.Gate           — the entry or exit point where a park or unpark request arrives.

Every one passes. Note two decisions hiding in that list.

Floor knows which spots are free, not ParkingLot. This is the responsibility that makes requirement N1 achievable. If the lot held one flat list of spots, "find a free medium spot" is a scan of the whole lot. With per-floor availability, the lot asks floors in order and stops at the first that has one.

Ticket records the session; it does not compute the fee. Fee computation needs pricing rules, which change on their own schedule. Giving Ticket a computeFee() that contains the rules would put a marketing decision inside a data record. Ticket holds the facts; the strategy reads them.

The vehicle hierarchy — and its limit

Java
public abstract class Vehicle {    private final String licensePlate;    public abstract VehicleSize getSize();     // getters omitted}public class Motorcycle extends Vehicle { public VehicleSize getSize() { return SMALL; } }public class Car        extends Vehicle { public VehicleSize getSize() { return MEDIUM; } }public class Truck      extends Vehicle { public VehicleSize getSize() { return LARGE; } }

This is a legitimate use of inheritance by the test in Inheritance, and its limits: a closed set, one level deep, mutually exclusive, differing in what they answer.

It stops being legitimate the moment a second dimension appears. An electric car is a car and needs charging — two axes. Do not write ElectricCar extends Car; add a boolean needsCharging or a ChargingRequirement field. The section's extensions return to this.

The class diagram

Fifteen minutes of modelling produces this. Draw the boxes first, then the lines, then the multiplicities, narrating throughout.

ParkingLot- levels: List- rates: RateStrategy+ park(Vehicle) Ticket+ unpark(Ticket) MoneyLevel- floor: int- spots: List+ findFree(VehicleSize) SpotSpot- id: String- size: VehicleSize- occupiedBy: Vehicle?+ fits(Vehicle) booleanTicket- id: String- spot: Spot- issuedAt: Instant«abstract»Vehicle- plate: String- size: VehicleSizeCarMotorcycle«interface»RateStrategy+ amountFor(Duration) MoneyHourlyRate+ amountFor(Duration) Money11..*11..*issuesreservesprices withnotationcomposition — owns; dies with itaggregation — has, but can outliveinheritance — is aSpot holds the vehicle by aggregation, notcomposition: deleting a spot must notdelete the car parked in it.
RateStrategy is an interface so pricing can change without touching ParkingLot — the extension the interviewer usually asks for at minute 40.

Reading the diagram

Composition, not aggregation, down the spine. A floor cannot exist without its lot; a spot cannot exist without its floor. Filled diamonds. Destroy the lot and the spots are meaningless — the test from Reading and drawing UML class diagrams.

Ticket associates rather than composes. A ticket references a spot and a vehicle but does not own either. Both outlive the ticket.

The right band is where change lives. Three vehicle types and three pricing rules are the two axes the requirements said would grow. Everything else is fixed structure.

What a weaker diagram looks like

Two versions come up constantly and are worth recognising in your own attempt:

  • No Floor. ParkingLot holds a flat List<ParkingSpot>. Availability per floor is now impossible without filtering, and requirement N1 fails.
  • Ticket holds the fee logic and PricingStrategy does not exist. Works today; the extension question breaks it immediately.