Object-Oriented Design Interview

Course Content

Object-Oriented Design Interview

14 sections · 29 lessons

Restaurant Management: scoping the capstone and separating the order from the kitchen ticket


The last problem in the course exercises every earlier skill at once, and has the most entities of any. That breadth makes its failure mode predictable: twenty shallow boxes and no method written. This lesson covers the scoping that prevents it, the requirements for the slice you keep, and the objects — including the one separation the whole design depends on.

The capstone, and what it is testingDesign arestaurant systemDine-in, or delivery?Reservations in scope?Kitchen routing?Billing and splits?
This prompt spans four subsystems, so it is scoping that is being tested, not modelling ability.

The capstone, and what it is testing

Every skill in this course appears here at once:

SkillWhere it appears
Scoping an unbounded prompt (Section 9)The prompt covers a dozen subsystems
The permanent-thing / per-use-record split (Sections 5, 9, 12)Table versus Seating, MenuItem versus OrderItem
Interacting state machines (Sections 7, 12, 13)Tables and order items run two lifecycles
Observer (Section 9)One status change reaches three screens
Command (The seven patterns that actually appear)Order modification and cancellation
Naming what you cut (Section 2)Inventory, payroll, and suppliers are all real and all out

Because of that breadth, the failure mode is specific: twenty boxes with no depth. A candidate who models reservations, seating, ordering, the kitchen, billing, inventory, and staff scheduling produces a wide, shallow diagram and never writes a method. The interviewer learns nothing.

The four questions that change the model

1. "Dine-in, takeaway, delivery, or all three?" Each adds a flow. Dine-in has tables and seating; takeaway has none; delivery adds a courier and an address. Assume dine-in as the core, and mention that takeaway is the same order without a table — which is a good sign your model is right.

2. "Are reservations, the kitchen display, and billing all in scope?" All three is the right scope for this round, because the interesting design is in how they interact. Say so and cut everything else.

3. "Single restaurant or a chain?" Assume single, and note where a chain would attach — the menu becomes shared, the tables stay per-location. That is the same Product/InventoryItem split from the grocery objects.

4. "How are bills split — by person, by item, evenly?" Ask, because "split the bill" is three different features. Assume even split and by-item as extensions.

Assumptions this lesson makes

  • One restaurant, dine-in focused, with takeaway noted as a variation.
  • Reservations, walk-ins, table assignment, ordering, kitchen routing, and billing in scope.
  • One kitchen with several stations (grill, fry, cold, dessert).
  • Servers carry devices that place and modify orders.
  • Inventory, purchasing, payroll, and staff scheduling are out of scope.

Requirements

Functional requirements

Text
1. Take a reservation for a party size at a time; assign a table on arrival2. Seat a party: mark the table occupied and open an order for it3. Take an order: add items with modifiers ("no onions"), quantities, and courses4. Route each item to the correct kitchen station as a ticket5. Track preparation: ordered → preparing → ready → served6. Generate a bill from the served items and take payment, possibly split

Requirement 3 hides two details worth catching early. Modifiers mean an order item is not merely a menu item reference — "burger, no onions, extra cheese" changes the kitchen ticket and possibly the price. Courses mean items have a serving order, which is the timing extension in Extensions.

Two details hidden in requirement threeOrderItem as a menu reference• An order line points at a dish• "No onions" has nowhere to live• Every item is cooked at onceOrderItem with modifiers• Modifiers change ticket and price• A course number gives serving order• The kitchen ticket is fully specified
Modifiers and courses are the two details that turn a menu reference into a real order line.

Non-functional requirements

N1. A table must never be double-booked or double-seated. Two servers seating two parties at table 12 is a visible, embarrassing failure. Same claim-do-not-peek shape as Sections 4 and 12.

N2. A status change must reach every screen that cares, without the kitchen knowing who they are. When the grill marks a steak ready, the server's device, the expediter's screen, and the bill must all reflect it. This is what forces Observer in Patterns applied.

N3. Modifying an order must be reversible and auditable. A cancelled item that is already cooking is a cost someone must account for. This is what makes Command the right pattern rather than a mutation.

What is cut

Text
CUT (named, not forgotten)- Inventory and stock depletion per dish (attaches to MenuItem)- Supplier orders and goods receiving- Payroll, rotas, and staff scheduling- Loyalty, marketing, and customer accounts- Table layout editing and floor-plan design- Accounting, tax filing, and end-of-day reconciliation beyond the bill

Six cuts against six requirements. That ratio is normal for this prompt, and writing both lists side by side on the board makes the scoping decision visible.

The scale numbers

A mid-sized restaurant, order of magnitude:

  • 30 tables, 8 servers, 200 covers (customers served) on a busy evening.
  • A few hundred orders per service, each with three to six items.
  • A rush where 60% of the evening's orders arrive within ninety minutes.

Nothing here is a scale problem, and saying so avoids a wasted tangent:

"There's no throughput challenge — a few hundred orders an evening is nothing. The pressure is on latency and correctness during the rush: a status change has to reach the server's device in seconds, and two servers must not seat the same table. That is where I'll spend the design."

Finding the objects

The candidate nouns

Restaurant, table, reservation, party, host, server, chef, station, menu, menu item, order, order item, modifier, course, kitchen ticket, bill, payment, customer, shift.

The separation this problem is about

The critical decision: the customer-facing order and the kitchen-facing ticket are two different things.

The instinct is one Order object that the kitchen also reads. It fails on four counts, and being able to list them is the answer to "why two classes?":

The orderThe kitchen ticket
Who owns itThe table / the partyOne kitchen station
What it groupsEverything the table asked forItems this station must cook
Its lifecycleOpen → served → billed → closedQueued → preparing → ready → collected
Its granularityThe whole table's food and drinkOne station's slice, possibly of several tables
Who reads itServer, cashier, customerOne chef at one station

A single order for a table of four might produce three tickets: two steaks to the grill, one salad to the cold station, and three drinks to the bar. Those three tickets have independent lifecycles — the salad is ready in two minutes and the steak in fourteen — and merging them into one status on the order makes "is the food ready?" unanswerable.

Java
public class Order {                       // customer-facing    private final String id;    private final Seating seating;         // which table, which party    private final List<OrderItem> items;    private OrderStatus status;            // OPEN, SERVED, BILLED, CLOSED    public Money runningTotal() { … }}public class OrderItem {                   // one line of the order    private final MenuItem menuItem;    private final int quantity;    private final List<Modifier> modifiers;   // "no onions", "extra cheese"    private final int courseNumber;           // 1 = starters, 2 = mains    private OrderItemStatus status;           // ORDERED, PREPARING, READY, SERVED, CANCELLED    private final Money priceCharged;         // snapshot, as in the grocery design}public class KitchenTicket {               // kitchen-facing    private final String id;    private final Station station;         // GRILL, FRY, COLD, DESSERT, BAR    private final List<OrderItem> items;   // this station's slice of one or more orders    private TicketStatus status;    private final Instant queuedAt;        // for the "oldest ticket" display}

Say the reasoning: "I'm separating the order from the kitchen ticket because they are read by different people, grouped differently, and have independent lifecycles. One order becomes three tickets across three stations, and the salad being ready has nothing to do with the steak."

Table and Seating: the split, for the fourth time

Table is a physical object with a number and a capacity, and it exists for years. Seating is one party's occupation of it: who, from when, for which order.

This is the same split as Seat/ShowSeat (Section 5), Product/InventoryItem (Section 9), and Locker/Reservation (Section 12). Fourth appearance. Naming it as a recurring pattern rather than rediscovering it is the transfer skill from the shipping locker opener:

"Same shape as the locker and reservation split — a physical thing reused many times a day needs a per-use record, or the history has nowhere to live."

The rest of the model

ClassIts one-sentence job
RestaurantHolds the tables, the menu, and the staff; thin
TableOne physical table: its number, capacity, and current state
ReservationA party's claim on a time slot and a party size
SeatingOne party's occupation of one table, and its order
Menu / MenuItemWhat can be ordered, its price, and its station
Order / OrderItemWhat one table asked for
KitchenTicketOne station's slice of the work
Bill / PaymentWhat is owed and what was paid
StaffServers, chefs, hosts — with a role

On Staff and roles: resist Server extends Staff and Chef extends Staff. People change roles between shifts, and a manager may serve during a rush. A Set<Role> field is the composition answer from Composition over inheritance — and an object cannot change its class at runtime, which is exactly what a shift change requires.

Restaurant- tables: List
- menu: Menu+ seat(Party) Table?+ openOrder(Table) OrderTable- number: int- seats: int- state: TableState+ occupy(Party)+ free()Order- table: Table- items: List- openedAt: Instant+ add(MenuItem, qty)+ total() Money+ close() BillOrderItem- menuItem: MenuItem- quantity: int- state: ItemState- notes: StringMenu- items: List+ available() ListMenuItem- name: String- price: Money- station: StationBill- lines- tip: Money+ split(int) List«abstract»Staff- name: String11..*for11..*of1..*closes intotakesnotationcomposition — owns; dies with itaggregation — has, but can outlivedepends on — uses transientlyOrderItem carries its own state because the kitchen finishes dishes one at a time, not one order at a time.
MenuItem is the thing on the menu; OrderItem is one instance of it on one table — separating them is what lets a dish be 86'd without editing orders.