Bird
Raised Fist0

Restaurant Management System

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
๐ŸŽฏ
Restaurant Management System Design
40 min ยท medium
medium

Design a system to manage restaurant operations including table reservations, menu management, order processing, kitchen notifications, billing with tax and discount strategies, and staff roles.

  • The system must support multiple tables with unique IDs and seating capacities.
  • Orders can contain multiple MenuItems and must notify Kitchen asynchronously on status changes.
  • Billing must support interchangeable tax and discount calculation strategies.
  • Staff includes Waiters who receive order status updates via Observer pattern.
  • MenuItem creation should be encapsulated using a Factory pattern.
๐Ÿ“‹
Guided Steps
1/5
Step 1
Design Table and MenuItem classes with proper state encapsulation
Define Table and MenuItem classes capturing their essential state and behaviors. Consider how to represent MenuItem types and Table status.
๐Ÿ’ก Hint
Use enums for fixed categories like TableStatus and MenuItemType to ensure type safety and exhaustive switch statements.
Use enum TableStatus {AVAILABLE, OCCUPIED, RESERVED} and enum MenuItemType {FOOD, DRINK} for compile-time safety; Table class holds volatile TableStatus status field to reflect concurrent updates.
Mid: Names enums and basic class fields. Senior: Explains why enum prevents runtime bugs and why volatile is needed for Table.status to ensure visibility across threads.
โš ๏ธCommon Wrong Answer
Using String for TableStatus or MenuItemType leads to runtime typo bugs and no compile-time exhaustive checks.
Step 2
Implement Order and Kitchen with Observer pattern for asynchronous notifications
Design Order and Kitchen classes so that Kitchen observes Order status changes and notifies Waiters asynchronously.
๐Ÿ’ก Hint
Use java.util.concurrent.CopyOnWriteArrayList for thread-safe observer list; Order status changes must be atomic and visible to Kitchen.
Order.status is a volatile enum OrderStatus; Kitchen maintains CopyOnWriteArrayList<Waiter> observers; Order notifies Kitchen on status change using synchronized method to atomically update status and notify observers.
Mid: Identifies Observer pattern usage. Senior: Details how volatile ensures visibility of OrderStatus changes and how synchronized prevents race conditions during status update and notification.
โš ๏ธCommon Wrong Answer
Not using volatile for OrderStatus causes Kitchen to see stale status; using non-thread-safe observer list causes ConcurrentModificationException.
Step 3
Encapsulate MenuItem creation using Factory pattern
Create a MenuItemFactory to encapsulate MenuItem instantiation logic, supporting future extensibility.
๐Ÿ’ก Hint
Factory method returns MenuItem subclass instances based on MenuItemType; use abstract class MenuItem with shared state.
abstract class MenuItem holds shared fields (id, name, price); MenuItemFactory uses static factory method createMenuItem(MenuItemType type, ...) returning concrete subclass; factory centralizes creation logic.
Mid: Recognizes Factory pattern for object creation. Senior: Explains why abstract class holds shared state (fields) which interface cannot in Java, enabling code reuse.
โš ๏ธCommon Wrong Answer
Creating MenuItem objects directly everywhere violates Single Responsibility Principle and scatters creation logic.
Step 4
Design Billing with Strategy pattern for tax and discount calculations
Implement Billing class that calculates total using interchangeable TaxStrategy and DiscountStrategy.
๐Ÿ’ก Hint
Define TaxStrategy and DiscountStrategy interfaces; Billing holds references to these strategies and delegates calculation.
Use interface TaxStrategy {double calculateTax(double amount);} and DiscountStrategy {double calculateDiscount(double amount);} to enable runtime strategy swapping; Billing class holds volatile references to strategies for thread-safe updates.
Mid: Identifies Strategy pattern usage. Senior: Explains why interfaces are used here (no state needed), and volatile references ensure visibility if strategies are updated concurrently.
โš ๏ธCommon Wrong Answer
Hardcoding tax and discount logic in Billing class violates Open-Closed Principle and makes future changes error-prone.
Step 5
Model Staff roles and their lifecycle relationships
Define Staff hierarchy including Waiter and Chef, and specify their relationships with Orders and Kitchen.
๐Ÿ’ก Hint
Use inheritance for Staff roles; Waiter observes Kitchen for order updates; Kitchen aggregates Orders but does not own them.
abstract class Staff with subclasses Waiter and Chef; Waiter registers as observer to Kitchen (aggregation relationship); Kitchen holds references to Orders (aggregation) but Orders exist independently.
Mid: Names inheritance and aggregation relationships. Senior: Explains lifecycle ownership-Orders can exist without Kitchen, so aggregation is appropriate; Waiter-Kitchen observer is association without ownership.
โš ๏ธCommon Wrong Answer
Using composition for Kitchen-Order causes Orders to be destroyed with Kitchen, violating real-world lifecycle.
๐Ÿ”Œ
API Design Challenge
Design RESTful APIs to manage tables, menu items, orders, kitchen notifications, billing, and staff management with concurrency and extensibility in mind.
  • Use resource-oriented endpoints like /tables, /menuitems, /orders with appropriate HTTP methods.
  • Design asynchronous notification mechanisms for kitchen updates, e.g., WebSocket or server-sent events.
  • Ensure billing APIs support dynamic tax and discount strategies via strategy pattern integration.
๐Ÿ“Š
Scoring Rubric
โ–ผ Show
Must Have - 60%
  • Use of enum for fixed categories to ensure type safety
  • Volatile fields for shared mutable state to guarantee visibility
  • Observer pattern with thread-safe observer list for Kitchen notifications
  • Abstract class MenuItem holding shared state instead of interface
  • Factory pattern encapsulating MenuItem creation logic
Good to Have - 30%
  • Strategy pattern for billing tax and discount calculations
  • Volatile references for billing strategies to support concurrency
  • Proper lifecycle modeling with aggregation and association
  • Synchronized methods for atomic status updates and notifications
  • Clear separation of Staff roles using inheritance
Bonus - 10%
  • Detailed concurrency explanation with thread interleaving scenarios
  • Extensibility considerations following SOLID principles
  • Use of CopyOnWriteArrayList for thread-safe observer management
Using String for enums leads to runtime typo bugs and no compile-time checks, causing bugs that are hard to detect and fix.
Not declaring volatile fields for shared mutable state causes visibility issues across threads, leading to stale reads and inconsistent behavior.
Hardcoding tax and discount logic in Billing class violates Open-Closed Principle, making future changes error-prone and requiring code modifications.
Using non-thread-safe observer lists causes ConcurrentModificationException under concurrent modifications, breaking notification reliability.
Using composition for Kitchen-Order lifecycle causes Orders to be destroyed with Kitchen, violating real-world lifecycle where Orders exist independently.
โœ…
Model Answer
โ–ผ Reveal

    • Use enum for fixed categories (TableStatus, MenuItemType) to ensure compile-time safety and prevent typo bugs.
    • Declare volatile fields (Table.status, Order.status) to guarantee visibility of state changes across threads.
    • Implement Observer pattern with thread-safe CopyOnWriteArrayList for Kitchen to notify Waiters asynchronously.
    • Use abstract class MenuItem to hold shared instance state; interface cannot hold fields in Java.
    • Encapsulate MenuItem creation in MenuItemFactory using static factory methods to centralize and extend creation logic.
    • Apply Strategy pattern with TaxStrategy and DiscountStrategy interfaces for flexible billing calculations.
    • Declare Billing's strategy references volatile to ensure thread-safe updates and visibility.
    • Model Staff roles using inheritance; use aggregation for Kitchen-Order and association for Waiter-Kitchen observer relationships to reflect lifecycle ownership.
    • Synchronize status update methods in Order to atomically change status and notify observers, preventing race conditions.
    • Avoid using Strings for types or statuses to prevent runtime errors and poor IDE support.

    Practice

    (1/5)
    1. In designing the Vehicle hierarchy for the booking system's parking module, should Vehicle be an abstract class or an interface, and why?
    easy
    A. Vehicle should be an interface because it only defines behavior without state.
    B. Vehicle should be an abstract class because it holds common state like license plate and enforces shared behavior.
    C. Vehicle should be a concrete class to allow direct instantiation of generic vehicles.
    D. Vehicle should be an enum to restrict vehicle types strictly.

    Solution

    1. Step 1: Identify if common state exists in Vehicle

      Vehicle has shared fields like license plate, size, or type, which require storage and partial implementation.
    2. Step 2: Abstract class fits because it allows shared state and behavior, while interfaces cannot hold instance state.

      Using an abstract class enforces common code reuse and prevents direct instantiation.
    3. Final Answer:

      Option B -> Option B
    4. Quick Check:

      Common state + shared behavior -> abstract class [check]
    Hint: State needs abstract class; behavior-only needs interface [check]
    Common Mistakes:
    2. Given a Vehicle abstraction that requires both state (e.g., speed) and behavior (e.g., accelerate()), should Vehicle be an abstract class or an interface in Java, and why?
    easy
    A. Vehicle should be an abstract class because interfaces cannot declare methods.
    B. Vehicle should be an interface because interfaces can hold state and provide default implementations.
    C. Vehicle should be an interface because abstract classes cannot have abstract methods.
    D. Vehicle should be an abstract class because it can hold shared state and provide common behavior implementations.

    Solution

    1. Step 1: Analyze state and behavior requirements

      Vehicle needs to hold state like speed and provide behavior like accelerate(), which requires shared fields and possibly implemented methods.
    2. Step 2: Choose between abstract class and interface

      Abstract classes can hold instance variables and provide method implementations, while interfaces (pre-Java 8) cannot hold state and only declare methods. Even with default methods, interfaces cannot hold mutable state.
    3. Final Answer:

      Option D -> Option D
    4. Quick Check:

      State + behavior -> abstract class fits better than interface [check]
    Hint: State needs fields -> use abstract class, not interface [check]
    Common Mistakes:
    3. Given a Vehicle abstraction that requires both state (like speed) and behavior (like accelerate), should Vehicle be an abstract class or an interface in Java, and why?
    easy
    A. Interface, because it allows multiple inheritance and can hold state variables.
    B. Interface, because it can define default methods with state variables initialized.
    C. Abstract class, because it can hold shared state and provide default behavior implementations.
    D. Abstract class, because interfaces cannot define any behavior in Java.

    Solution

    1. Step 1: Analyze state and behavior requirements

      Vehicle needs to hold state like speed and provide behavior like accelerate with shared code, which requires fields and method implementations.
    2. Step 2: Compare abstract class vs interface capabilities

      Abstract classes can have instance variables and concrete methods; interfaces cannot hold instance state (only constants) and default methods cannot maintain state.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      State + behavior with shared code -> abstract class [check]
    Hint: State needs fields? Use abstract class, not interface [check]
    Common Mistakes:
    4. You need to add support for ElectricCar and ChargingSpot in your existing parking system without modifying existing classes. What is the minimum change to support this extensibility in Java?
    hard
    A. Add a boolean isElectric flag to Vehicle and add conditional logic in SpotCompatibility.
    B. Modify Vehicle base class to add electric-specific fields and methods, and update SpotCompatibility accordingly.
    C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map; no existing classes modified.
    D. Create a new ElectricVehicle interface and modify existing Vehicle class to implement it.

    Solution

    1. Step 1: Identify extensibility without modifying existing classes

      Adding new enum values and new subclass ElectricCar extends Vehicle allows extension without changing existing class code.
    2. Step 2: Update SpotCompatibility map externally

      Updating compatibility map to include new types supports new logic without modifying existing classes, preserving OCP.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      New enums + subclass + external map update -> no existing class changes [check]
    Hint: New enums + subclass + map update -> no existing class change [check]
    Common Mistakes:
    5. To add ElectricCar needing ChargingSpot compatibility, what is the minimum change to the current design without modifying existing classes?
    hard
    A. Create a new ElectricParkingLot subclass handling charging spots, duplicating logic
    B. Modify Vehicle class to add electric-specific fields and methods, breaking OCP
    C. Add ELECTRIC_CAR to VehicleType, CHARGING to SpotType, create ElectricCar extending Vehicle, and update SpotCompatibility.COMPATIBILITY_MAP
    D. Add a boolean isElectric flag to Vehicle and add conditional logic in ParkingLot

    Solution

    1. Step 1: Identify extensibility without modifying existing classes

      Adding new vehicle and spot types via enums and creating a new subclass ElectricCar extends functionality without changing existing code.
    2. Step 2: Update compatibility map externally

      Updating SpotCompatibility.COMPATIBILITY_MAP to include new mappings allows the system to recognize charging spots without modifying core logic.
    3. Final Answer:

      Option C -> Option C
    4. Quick Check:

      New enums + subclass + compatibility map update -> minimal change, OCP preserved [check]
    Hint: New enums + subclass + map update -> extend without modify [check]
    Common Mistakes:
    Recommended

    Ready to prove it?

    Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

    10 questions~5 mineasy hard