Restaurant Management
Design the system behind a dine-in restaurant: seat a party at a table, take an order off the menu, fire it to the kitchen, and serve it. The prompt has three actors - host, server, kitchen - who each touch the same order at a different point in its life, which is exactly where a design either stays clean or turns into one class with everyone's logic crammed inside it.
Requirements
Functional
- A
TableisFREE,RESERVED, orOCCUPIED; seating a party changes it toOCCUPIEDand clearing it changes it back toFREE. - An
Orderis opened against an occupied table and holds a list ofOrderItems, each referencing aMenuItemand a quantity. - Once submitted, an order moves
PLACED -> IN_KITCHEN -> READY -> SERVED; items cannot be added after it leavesPLACED. - The kitchen sees only items it needs to prepare, grouped by station (grill, cold, dessert), not the whole order as a flat undifferentiated list.
Non-functional
- A
MenuItemgoing 86'd (out of stock) mid-service must block new orders for it without the table or order code needing to know inventory exists. - Kitchen station routing (today: 3 fixed stations) must extend to new stations without
editing
OrderorOrderItem.
Design
Order is the object that outlives a single interaction between any two actors: the host
opens the table, the server builds and submits the order, the kitchen advances its status,
and the server serves it - Order is the one thing all four steps read and mutate,
exactly the role Ticket plays in Parking Lot as the
object that carries state across a gap in time. Each MenuItem carries its own
station, so grouping for the kitchen view is a partition, not a lookup table maintained
somewhere else.
- 1Seating only ever touches the table - it has no idea an order will follow.
- 2The server opens an order against the now-occupied table; this is the object every later actor shares.
- 3Each add checks the order is still PLACED and the item is still available, both inside this one call.
- 4Submitting flips the order to IN_KITCHEN; addItem() is no longer legal from this point on.
- 5The kitchen asks for its own view of the same order - grouped by station, never the whole flat list.
- 6The kitchen advances status when done; it never edits the item list, only the status it owns the transition into.
Availability is a property of MenuItem, checked once at the moment an item is added to
an order - the table and the order status machinery never reference stock at all.
Class diagram
Code
Design decisions
OrderStatustransitions are enforced onOrder, and adding an item is only legal inPLACED. Once an order reaches the kitchen, the printed ticket is the source of truth for what's cooking; lettingaddItem()succeed afterIN_KITCHENwould silently desync the two. Checking status insideaddItem()itself means there's no code path that can add an item to a submitted order, not even a mistake in a future caller.MenuItem.availableis a flag the item owns, checked ataddItem()time - not a separate inventory serviceOrdercalls into. For this scope, availability is binary and item-local, so putting it on the item keeps the dependency one-directional:Orderreads a field onMenuItemit already holds a reference to, rather than reaching out to a new subsystem.- Kitchen station grouping is a
groupByStation()query overOrderItem.menuItem.station, not a field that lives onOrder. The order itself has no concept of stations; the grouping is a view the kitchen asks for, computed from data that's already there. Adding a fourth station is a new enum value, not a new field anywhere. - What's missing for a real system: splitting a check across multiple diners at one
table needs
Orderto support partial-item ownership this design doesn't model (every item here belongs to the table's one order), and course timing (appetizers fire to the kitchen before entrees) needs per-item submission rather than the whole order moving toIN_KITCHENat once - both left out to keep the four-status lifecycle the whole focus.