problemhardood

Object-Oriented Design for a Restaurant Management System

Problem

Design an object-oriented system for a multi-branch restaurant to manage menus, table layouts, reservations, orders (meals per seat), billing, and notifications for upcoming reservations and status changes.

Solution

1. Requirements Analysis

Functional Requirements:

  • Manage multiple restaurant branches each with its own menu and seating layouts.
  • Maintain hierarchical menu: sections and items with pricing updates.
  • Allow receptionists to search availability and create/cancel reservations; support check-in.
  • Track free vs reserved vs occupied tables and seats; support multiple seating arrangements.
  • Allow waiters to create/update orders and add meals composed of meal items per seat.
  • Support chefs viewing and working on orders (order status progression).
  • Generate bills/checks and process payments (cash, card, check) and record payment status.
  • Send notifications for upcoming reservations or cancellations.

Non-Functional (implicit):

  • Consistent state transitions (e.g., reservation status flow, order status lifecycle).
  • Extensibility for additional payment types or seat categories.

2. Use Case Diagram

Actors: Receptionist, Waiter, Manager, Chef, Cashier, System, Customer.

Primary Use Cases: Add/Modify Tables, Search Tables, Create Reservation, Cancel Reservation, Check-In, Place Order, Update Order, Make Payment, Send Notification.

graph TD
    subgraph RMS[Restaurant Management System]
        UC_Add(Add/Modify Tables)
        UC_Search(Search Tables)
        UC_Reserve(Create Reservation)
        UC_Cancel(Cancel Reservation)
        UC_CheckIn(Check-In)
        UC_Order(Place/Update Order)
        UC_Pay(Make Payment)
        UC_Notify(Send Notification)
    end
    Receptionist --> UC_Add
    Receptionist --> UC_Search
    Receptionist --> UC_Reserve
    Receptionist --> UC_Cancel
    Receptionist --> UC_CheckIn
    Waiter --> UC_Order
    Chef --> UC_Order
    Cashier --> UC_Pay
    System --> UC_Notify
    Manager --> UC_Add
    Customer --> UC_Reserve
    Customer --> UC_Pay

3. Class Diagram

Core Classes & Responsibilities:

  • Restaurant: Aggregate of Branches; high-level add/remove branch operations.
  • Branch: Holds Menu(s), TableCharts, and localized staff.
  • Menu / MenuSection / MenuItem: Hierarchical menu representation with pricing.
  • Table / TableSeat: Physical seating; capacity tracking and availability queries.
  • Reservation: Booking details, status transitions, associated tables, notifications.
  • Order / Meal / MealItem / Check: Captures ordered items per seat and billing artifacts.
  • Account / Person / Employee (Receptionist, Waiter, Manager, Chef, Cashier): Actor identities and roles.
  • Notification: Reminder or status update dispatching (skeleton only).
classDiagram
    class Restaurant {
        +name: String
        +branches: List<Branch>
        +addBranch(branch)
    }
    class Branch {
        +name: String
        +location: Address
        +menus: List<Menu>
        +tableCharts: List<TableChart>
    }
    class Menu {
        +id: int
        +title: String
        +sections: List<MenuSection>
        +addSection(section)
    }
    class MenuSection {
        +id: int
        +title: String
        +items: List<MenuItem>
        +addItem(item)
    }
    class MenuItem {
        +id: int
        +title: String
        +price: double
        +updatePrice(p)
    }
    class Table {
        +id: int
        +maxCapacity: int
        +status: TableStatus
        +seats: List<TableSeat>
        +isFree()
    }
    class TableSeat {
        +number: int
        +type: SeatType
        +updateType(type)
    }
    class Reservation {
        +id: int
        +peopleCount: int
        +status: ReservationStatus
        +tables: List<Table>
        +updatePeopleCount(c)
    }
    class Order {
        +id: int
        +status: OrderStatus
        +meals: List<Meal>
        +addMeal(meal)
    }
    class Meal {
        +id: int
        +seat: TableSeat
        +items: List<MealItem>
        +addMealItem(item)
    }
    class MealItem {
        +id: int
        +quantity: int
        +menuItem: MenuItem
        +updateQuantity(q)
    }
    class Check {
        +total(): double
    }
    class Notification {
        +message: String
        +send()
    }
    class Account {
        +id: String
        +status: AccountStatus
        +resetPassword()
    }
    class Employee {
        +employeeId: String
    }
    Restaurant "1" -- "*" Branch : has
    Branch "1" -- "*" Menu : owns
    Menu "1" -- "*" MenuSection : contains
    MenuSection "1" -- "*" MenuItem : lists
    Branch "1" -- "*" TableChart : layouts
    Table "1" -- "*" TableSeat : contains
    Reservation "1" -- "*" Table : reserves
    Order "1" -- "*" Meal : aggregates
    Meal "1" -- "*" MealItem : consists
    MealItem "*" -- "1" MenuItem : references

4. Activity Diagrams

Activity: Place Order

graph TD
    A[Waiter selects table] --> B{Table free?}
    B -- Yes --> C[Create Order]
    B -- No --> D[Show error]
    C --> E[Add Meals per Seat]
    E --> F[Submit Order]
    F --> G[Chef Prepares]

Activity: Make Reservation

graph TD
    R1[Receptionist searches tables] --> R2{Available?}
    R2 -- Yes --> R3[Collect Customer Details]
    R2 -- No --> R4[Suggest Alternate]
    R3 --> R5[Create Reservation]
    R5 --> R6[Send Confirmation Notification]

Activity: Cancel Reservation

graph TD
    C1[Customer/Receptionist selects reservation] --> C2{Within cancel window?}
    C2 -- Yes --> C3[Update Status to CANCELED]
    C2 -- No --> C4[Mark ABANDONED or Reject]
    C3 --> C5[Release Tables]
    C5 --> C6[Send Cancellation Notification]

5. High-Level Code Implementation

Java

enum ReservationStatus { REQUESTED, PENDING, CONFIRMED, CHECKED_IN, CANCELED, ABANDONED }
enum SeatType { REGULAR, KID, ACCESSIBLE, OTHER }
enum OrderStatus { RECEIVED, PREPARING, COMPLETED, CANCELED }
enum TableStatus { FREE, RESERVED, OCCUPIED, OTHER }
enum AccountStatus { ACTIVE, CLOSED, CANCELED, BLACKLISTED, BLOCKED }

class Address {
    private String street; private String city; private String state; private String zip; private String country;
    Address(String street, String city, String state, String zip, String country) {
        this.street = street; this.city = city; this.state = state; this.zip = zip; this.country = country;
    }
}

class Account {
    private String id; private String password; private AccountStatus status; private Address address;
    Account(String id, String password, Address address) { this.id=id; this.password=password; this.address=address; this.status=AccountStatus.ACTIVE; }
    void resetPassword() { /* ... */ }
}

abstract class Person { protected String name; protected String email; protected String phone; }
abstract class Employee extends Person { protected String employeeId; protected Account account; Employee(String id, Account acc, String name, String email, String phone){ this.employeeId=id; this.account=acc; this.name=name; this.email=email; this.phone=phone; }}
class Receptionist extends Employee { Receptionist(String id, Account acc, String n, String e, String p){ super(id,acc,n,e,p);} void createReservation(){ } }
class Manager extends Employee { Manager(String id, Account acc, String n, String e, String p){ super(id,acc,n,e,p);} void addEmployee(Employee emp){ } }
class Chef extends Employee { Chef(String id, Account acc, String n, String e, String p){ super(id,acc,n,e,p);} void takeOrder(Order order){ } }

class MenuItem { int id; String title; String description; double price; void updatePrice(double p){ this.price = p; } }
class MenuSection { int id; String title; java.util.List<MenuItem> items = new java.util.ArrayList<>(); void addItem(MenuItem mi){ items.add(mi);} }
class Menu { int id; String title; java.util.List<MenuSection> sections = new java.util.ArrayList<>(); void addSection(MenuSection s){ sections.add(s);} }

class TableSeat { int number; SeatType type = SeatType.REGULAR; void updateType(SeatType t){ this.type = t; } }
class Table { int id; int maxCapacity; TableStatus status = TableStatus.FREE; java.util.List<TableSeat> seats = new java.util.ArrayList<>(); boolean isFree(){ return status==TableStatus.FREE; } }

class MealItem { int id; int quantity; MenuItem menuItem; void updateQuantity(int q){ this.quantity=q; } }
class Meal { int id; TableSeat seat; java.util.List<MealItem> items = new java.util.ArrayList<>(); void addMealItem(MealItem mi){ items.add(mi);} }
class Check { double total(){ return 0.0; } }
class Order { int id; OrderStatus status; java.util.List<Meal> meals = new java.util.ArrayList<>(); void addMeal(Meal m){ meals.add(m);} }

class Reservation { int id; int peopleCount; ReservationStatus status = ReservationStatus.REQUESTED; java.util.List<Table> tables = new java.util.ArrayList<>(); void updatePeopleCount(int c){ peopleCount=c; } }
class Notification { String message; void send(){ } }

class Restaurant { String name; java.util.List<Branch> branches = new java.util.ArrayList<>(); void addBranch(Branch b){ branches.add(b);} }
class Branch { String name; Address location; java.util.List<Menu> menus = new java.util.ArrayList<>(); java.util.List<Table> tables = new java.util.ArrayList<>(); }
class TableChart { int id; java.util.List<Table> snapshot = new java.util.ArrayList<>(); }

Python

from enum import Enum
from typing import List

class ReservationStatus(Enum):
    REQUESTED = 1; PENDING = 2; CONFIRMED = 3; CHECKED_IN = 4; CANCELED = 5; ABANDONED = 6
class SeatType(Enum):
    REGULAR = 1; KID = 2; ACCESSIBLE = 3; OTHER = 4
class OrderStatus(Enum):
    RECEIVED = 1; PREPARING = 2; COMPLETED = 3; CANCELED = 4
class TableStatus(Enum):
    FREE = 1; RESERVED = 2; OCCUPIED = 3; OTHER = 4
class AccountStatus(Enum):
    ACTIVE = 1; CLOSED = 2; CANCELED = 3; BLACKLISTED = 4; BLOCKED = 5

class Address:
    def __init__(self, street: str, city: str, state: str, zip_code: str, country: str) -> None:
        self.street = street; self.city = city; self.state = state; self.zip_code = zip_code; self.country = country

class Account:
    def __init__(self, id: str, password: str, address: Address) -> None:
        self.id = id; self.password = password; self.address = address; self.status = AccountStatus.ACTIVE
    def reset_password(self) -> None:
        pass

class Person:
    def __init__(self, name: str, email: str, phone: str) -> None:
        self.name = name; self.email = email; self.phone = phone

class Employee(Person):
    def __init__(self, employee_id: str, account: Account, name: str, email: str, phone: str) -> None:
        super().__init__(name, email, phone); self.employee_id = employee_id; self.account = account

class Receptionist(Employee):
    def create_reservation(self) -> None: pass
class Manager(Employee):
    def add_employee(self) -> None: pass
class Chef(Employee):
    def take_order(self) -> None: pass

class MenuItem:
    def __init__(self, id: int, title: str, description: str, price: float) -> None:
        self.id = id; self.title = title; self.description = description; self.price = price
    def update_price(self, price: float) -> None:
        self.price = price

class MenuSection:
    def __init__(self, id: int, title: str, description: str) -> None:
        self.id = id; self.title = title; self.description = description; self.items: List[MenuItem] = []
    def add_menu_item(self, item: MenuItem) -> None:
        self.items.append(item)

class Menu:
    def __init__(self, id: int, title: str, description: str) -> None:
        self.id = id; self.title = title; self.description = description; self.sections: List[MenuSection] = []
    def add_menu_section(self, section: MenuSection) -> None:
        self.sections.append(section)

class TableSeat:
    def __init__(self, number: int, seat_type: SeatType = SeatType.REGULAR) -> None:
        self.number = number; self.seat_type = seat_type
    def update_seat_type(self, seat_type: SeatType) -> None:
        self.seat_type = seat_type

class Table:
    def __init__(self, id: int, max_capacity: int) -> None:
        self.id = id; self.max_capacity = max_capacity; self.status = TableStatus.FREE; self.seats: List[TableSeat] = []
    def is_free(self) -> bool: return self.status == TableStatus.FREE

class MealItem:
    def __init__(self, id: int, quantity: int, menu_item: MenuItem) -> None:
        self.id = id; self.quantity = quantity; self.menu_item = menu_item
    def update_quantity(self, quantity: int) -> None:
        self.quantity = quantity

class Meal:
    def __init__(self, id: int, seat: TableSeat) -> None:
        self.id = id; self.seat = seat; self.items: List[MealItem] = []
    def add_meal_item(self, item: MealItem) -> None:
        self.items.append(item)

class Check:
    def __init__(self) -> None: pass
    def total(self) -> float: return 0.0

class Order:
    def __init__(self, id: int, status: OrderStatus, table: Table, waiter: Receptionist, chef: Chef) -> None:
        self.id = id; self.status = status; self.meals: List[Meal] = []; self.table = table; self.waiter = waiter; self.chef = chef; self.check = Check()
    def add_meal(self, meal: Meal) -> None:
        self.meals.append(meal)

class Reservation:
    def __init__(self, id: int, people_count: int) -> None:
        self.id = id; self.people_count = people_count; self.status = ReservationStatus.REQUESTED; self.tables: List[Table] = []
    def update_people_count(self, count: int) -> None:
        self.people_count = count

class Notification:
    def __init__(self, message: str) -> None:
        self.message = message
    def send(self) -> None: pass

class Restaurant:
    def __init__(self, name: str) -> None:
        self.name = name; self.branches: List[Branch] = []
    def add_branch(self, branch: 'Branch') -> None:
        self.branches.append(branch)

class Branch:
    def __init__(self, name: str, location: Address) -> None:
        self.name = name; self.location = location; self.menus: List[Menu] = []; self.tables: List[Table] = []

class TableChart:
    def __init__(self, id: int) -> None:
        self.id = id; self.snapshot: List[Table] = []

Enums, data types, and constants: Here are the required enums, data types, and constants:

from enum import Enum


class ReservationStatus(Enum):
    REQUESTED, PENDING, CONFIRMED, CHECKED_IN, CANCELED, ABANDONED = 1, 2, 3, 4, 5, 6


class SeatType(Enum):
    REGULAR, KID, ACCESSIBLE, OTHER = 1, 2, 3, 4


class OrderStatus(Enum):
    RECEIVED, PREPARING, COMPLETED, CANCELED, NONE = 1, 2, 3, 4, 5


class TableStatus(Enum):
    FREE, RESERVED, OCCUPIED, OTHER = 1, 2, 3, 4


class AccountStatus(Enum):
    ACTIVE, CLOSED, CANCELED, BLACKLISTED, BLOCKED = 1, 2, 3, 4, 5


class PaymentStatus(Enum):
    UNPAID, PENDING, COMPLETED, FILLED, DECLINED, CANCELLED, ABANDONED, SETTLING, SETTLED, REFUNDED = 1, 2, 3, 4, 5, 6, 7, 8, 9, 10


class Address:
    def __init__(self, street, city, state, zip_code, country):
        self.__street_address = street
        self.__city = city
        self.__state = state
        self.__zip_code = zip_code
        self.__country = country

Account, Person, Employee, Receptionist, Manager, and Chef: These classes represent the different people that interact with our system:

from abc import ABC
from datetime import datetime
from .constants import *


# For simplicity, we are not defining getter and setter functions. The reader can
# assume that all class attributes are private and accessed through their respective
# public getter methods and modified only through their public methods function.


class Account:
    def __init__(self, id, password, address, status=AccountStatus.Active):
        self.__id = id
        self.__password = password
        self.__address = address
        self.__status = status

    def reset_password(self):
        None


class Person(ABC):
    def __init__(self, name, email, phone):
        self.__name = name
        self.__email = email
        self.__phone = phone


class Employee(ABC, Person):
    def __init__(self, id, account, name, email, phone):
        super().__init__(name, email, phone)
        self.__employee_id = id
        self.__date_joined = datetime.date.today()
        self.__account = account


class Receptionist(Employee):
    def __init__(self, id, account, name, email, phone):
        super().__init__(id, account, name, email, phone)

    def create_reservation(self):
        None

    def search_customer(self, name):
        None


class Manager(Employee):
    def __init__(self, id, account, name, email, phone):
        super().__init__(id, account, name, email, phone)

    def add_employee(self):
        None


class Chef(Employee):
    def __init__(self, id, account, name, email, phone):
        super().__init__(id, account, name, email, phone)

    def take_order(self):
        None

Restaurant, Branch, Kitchen, TableChart: These classes represent the top-level classes of the system

class Kitchen:
    def __init__(self, name):
        self.__name = name
        self.__chefs = []

    def assign_chef(self, chef):
        None


class Branch:
    def __init__(self, name, location, kitchen):
        self.__name = name
        self.__location = location
        self.__kitchen = kitchen

    def add_table_chart(self):
        None


class Restaurant:
    def __init__(self, name):
        self.__name = name
        self.__branches = []

    def add_branch(self, branch):
        None


class TableChart:
    def __init__(self, id):
        self.__table_chart_id = id
        self.__table_chart_image = []

    def print(self):
        None

Table, TableSeat, and Reservation: Each table can have multiple seats and customers can make reservations for tables:

from datetime import datetime
from .constants import *


class Table:
    def __init__(self, id, max_capacity, location_identifier, status=TableStatus.FREE):
        self.__table_id = id
        self.__max_capacity = max_capacity
        self.__location_identifier = location_identifier
        self.__status = status
        self.__seats = []

    def is_table_free(self):
        None

    def add_reservation(self):
        None

    def search(self, capacity, start_time):
        # return all tables with the given capacity and availability
        None


class TableSeat:
    def __init__(self):
        self.__table_seat_number = 0
        self.__type = SeatType.REGULAR

    def update_seat_type(self, seat_type):
        None


class Reservation:
    def __init__(self, id, people_count, notes, customer):
        self.__reservation_id = id
        self.__time_of_reservation = datetime.now()
        self.__people_count = people_count
        self.__status = ReservationStatus.REQUESTED
        self.__notes = notes
        self.__checkin_time = datetime.now()
        self.__customer = customer
        self.__tables = []
        self.__notifications = []

    def update_people_count(self, count):
        None

Menu, MenuSection, and MenuItem: Each restaurant branch will have its own menu, each menu will have multiple menu sections, which will contain menu items:

class MenuItem:
    def __init__(self, id, title, description, price):
        self.__menu_item_id = id
        self.__title = title
        self.__description = description
        self.__price = price

    def update_price(self, price):
        None


class MenuSection:
    def __init__(self, id, title, description):
        self.__menu_section_id = id
        self.__title = title
        self.__description = description
        self.__menu_items = []

    def add_menu_item(self, menu_item):
        None


class Menu:
    def __init__(self, id, title, description):
        self.__menu_id = id
        self.__title = title
        self.__description = description
        self.__menu_sections = []

    def add_menu_section(self, menu_section):
        None

    def print(self):
        None

Order, Meal, and MealItem: Each order will have meals for table seats:

from datetime import datetime


class MealItem:
    def __init__(self, id, quantity, menu_item):
        self.__meal_item_id = id
        self.__quantity = quantity
        self.__menu_item = menu_item

    def update_quantity(self, quantity):
        None


class Meal:
    def __init__(self, id, seat):
        self.__meal_id = id
        self.__seat = seat
        self.__menu_items = []

    def add_meal_item(self, meal_item):
        None


class Check():
    def __init__(self):
        None


class Order:
    def __init__(self, id, status, table, waiter, chef):
        self.__order_id = id
        self.__OrderStatus = status
        self.__creation_time = datetime.now()

        self.__meals = []
        self.__table = table
        self.__waiter = waiter
        self.__chef = chef
        self.__check = Check()

    def add_meal(self, meal):
        None

    def remove_meal(self, meal):
        None

    def get_status(self):
        return self.__OrderStatus

    def set_status(self, status):
        None

Source https://github.com/tssovi/grokking-the-object-oriented-design-interview

Comments