Chaturmind
LearnDSASystem DesignInterview PrepDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth
  • Java Interview Prep

Company

  • About
  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

👥10,050visitors

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsMachine Coding Exercises
✓ FreeIntermediate· 7 min read

Restaurant Management System

Restaurant/Menu/Order/Table/Kitchen classes, order status flow as State pattern, and separating dine-in from takeout/delivery without duplicating logic.

Published September 23, 2026


Restaurant Management System

Core classes

class Menu { List<MenuItem> items; }
class MenuItem { String name; double price; boolean available; }
class Table { int number; int capacity; TableStatus status; } // dine-in only
class Order {
    List<OrderLine> lines;
    OrderType type; // DINE_IN, TAKEOUT, DELIVERY
    Table table; // null for takeout/delivery
    OrderStatus status;
}

Advertisement

Order status flow as State pattern

interface OrderState {
    OrderState advance(Order order); // returns the NEXT state — the transition logic lives per-state
}

class PlacedState implements OrderState {
    public OrderState advance(Order order) { notifyKitchen(order); return new PreparingState(); }
}
class PreparingState implements OrderState {
    public OrderState advance(Order order) { return new ReadyState(); }
}
class ReadyState implements OrderState {
    public OrderState advance(Order order) {
        return order.type == OrderType.DINE_IN ? new ServedState() : new AwaitingPickupOrDeliveryState();
    }
}

The placed → preparing → ready → served flow is a direct State pattern application (see State Pattern) — each state knows only its own valid next transition, and ReadyState's branch on order.type is the one place order-type-specific flow divergence needs to be expressed, not scattered across the whole class.

Separating dine-in from takeout/delivery without duplicating logic

Rather than two entirely separate class hierarchies (DineInOrder vs TakeoutOrder), a single Order class with an OrderType field and one branch point (in ReadyState, shown above) keeps the shared 90% of order-handling logic (placement, kitchen notification, line items, pricing) unified, while only the genuinely divergent final step (served to a table vs handed off for pickup/delivery) differs. This is a judgment call worth naming explicitly: full separation into distinct class hierarchies would be over-engineering for a difference this localized — the State pattern's per-state branch is a proportionate amount of structure for one point of real divergence, not the whole flow.

Making the state machine enforce the rules

The state classes above always move forward. A real order also gets cancelled, and cancellation is only allowed at certain points: free before the kitchen starts, and needing a manager afterwards. Encoding the allowed transitions in one place makes invalid ones impossible, rather than relying on every caller to check:

enum OrderStatus {
    PLACED, PREPARING, READY, SERVED, AWAITING_PICKUP, OUT_FOR_DELIVERY, COMPLETED, CANCELLED;

    private static final Map<OrderStatus, Set<OrderStatus>> ALLOWED = Map.of(
        PLACED,           Set.of(PREPARING, CANCELLED),
        PREPARING,        Set.of(READY, CANCELLED),            // cancelling now wastes food: needs approval
        READY,            Set.of(SERVED, AWAITING_PICKUP, OUT_FOR_DELIVERY),
        SERVED,           Set.of(COMPLETED),
        AWAITING_PICKUP,  Set.of(COMPLETED),
        OUT_FOR_DELIVERY, Set.of(COMPLETED),
        COMPLETED,        Set.of(),
        CANCELLED,        Set.of());

    boolean canMoveTo(OrderStatus next) { return ALLOWED.get(this).contains(next); }
}

class Order {
    private OrderStatus status = OrderStatus.PLACED;
    private final List<OrderEvent> history = new ArrayList<>();

    void moveTo(OrderStatus next, String actor) {
        if (!status.canMoveTo(next))
            throw new IllegalStateException("Cannot move order from " + status + " to " + next);
        history.add(new OrderEvent(status, next, actor, Instant.now()));
        status = next;
    }
}

This transition-table form is a lighter alternative to one class per state. Use it when states carry little behaviour of their own. Switch to full State-pattern classes when each state has substantial, different behaviour, for example PreparingState reacting to "item out of stock" by notifying the waiter and proposing substitutes. Either way, the history list gives you an audit trail, and makes answering "why was this order late?" possible.

The kitchen: routing lines to stations

A kitchen isn't one queue. Grill, fryer, cold station and bar prepare different lines of the same order in parallel, and the order is READY only when all of its lines are:

enum Station { GRILL, FRYER, COLD, BAR }

class MenuItem { String name; Money price; Station station; Duration prepTime; boolean available; }

class OrderLine {
    final MenuItem item; final int qty; boolean done;
    OrderLine(MenuItem item, int qty) { this.item = item; this.qty = qty; }
}

class Kitchen {
    private final Map<Station, Queue<OrderLine>> queues = new EnumMap<>(Station.class);
    private final Map<OrderLine, Order> owner = new HashMap<>();

    Kitchen() { for (Station s : Station.values()) queues.put(s, new ArrayDeque<>()); }

    void accept(Order order) {
        for (OrderLine line : order.lines()) {
            queues.get(line.item.station).add(line);   // fan out to stations
            owner.put(line, order);
        }
        order.moveTo(OrderStatus.PREPARING, "kitchen");
    }

    void markDone(OrderLine line) {
        line.done = true;
        Order order = owner.remove(line);
        if (order.lines().stream().allMatch(l -> l.done))   // fan in: all stations finished
            order.moveTo(OrderStatus.READY, "kitchen");
    }
}

This fan-out/fan-in structure is the heart of a kitchen display system. Extensions fit naturally: order the station queues by priority (delivery orders with a waiting rider first), or estimate readiness time from the longest prepTime among an order's lines.

Bills and splitting

Keep billing separate from the order. A Bill is computed from order lines plus a tax and service-charge policy (a Strategy, since it varies by region and order type). Splitting a bill is a list of BillShares whose amounts must add up exactly to the total. Use a money type in the smallest currency unit (paise, cents), and assign rounding remainders deterministically, so three-way splits don't lose or invent a paisa.

Follow-up questions this topic invites — and their answers

Q: Why does Table exist as a separate class rather than just a table number field on Order? A: Table has its own independent state (capacity, current occupancy status) that needs tracking regardless of any specific order — a restaurant needs to know which tables are free for seating NEW parties, which is a Table-level concern that exists before, during, and after any single order's lifecycle, not something that belongs embedded in Order.

Q: How would delivery add a DeliveryPartner assignment step to this flow, connecting to Food Delivery Order Matching? A: AwaitingPickupOrDeliveryState's advance() for a DELIVERY-type order would trigger a matching call (see Food Delivery Order Matching's MatchingEngine) before transitioning further — this is exactly the LLD-to-HLD connection point that class design worth naming: the class model provides the hook, the actual matching algorithm is a separate concern layered on top.

Q: What happens if the kitchen marks an order ready but a dine-in customer has already left (a real edge case)? A: Worth naming as a scenario requiring an explicit state or handling path (e.g. a 'CancelledAfterReady' resolution, or holding the prepared order for a return), rather than assuming the happy-path transition sequence always completes — a strong interview answer names edge cases like this explicitly even without fully designing the resolution.

Q: Should MenuItem availability (available: boolean) be checked at order-placement time or continuously? A: At minimum, checked at placement time (rejecting an order line for an unavailable item) — a more robust design would also handle an item becoming unavailable mid-preparation (the kitchen discovers it's out of an ingredient), which argues for treating availability changes as another event PlacedState/PreparingState might need to react to, not just a static field checked once.

Q: Transition table or State-pattern classes: which should I use in an interview? A: Start with a transition table (an enum plus allowed next states) when states differ mainly in which moves are legal. It's compact and easy to test exhaustively. Move to State classes when individual states need significant behaviour, and say explicitly why you're making that trade.

Q: How does the kitchen know when a multi-station order is ready? A: Each order line is routed to its station's queue, and marked done independently. After each completion, check whether all of that order's lines are done. The last one moves the order to READY. That's a fan-out/fan-in pattern.

Q: Why use integer money amounts instead of double for bills? A: Binary floating point can't represent most decimal fractions exactly, so sums and splits drift (0.1 + 0.2 ≠ 0.3). Store amounts as integer minor units (or BigDecimal with explicit rounding) and allocate split remainders deterministically.

Advertisement

Previous

Design an Inventory Management System

Next

Food Delivery Order Matching

AI Tutor

Lesson: Restaurant Management System

Quick actions

AI responses can be inaccurate. Verify critical information.