Object-Oriented Design• Patterns: Factory, Observer, Strategy
Restaurant
Medium
Problem Summary
Design a comprehensive Restaurant Management System handling table seating, digital orders, Kitchen Display System (KDS) routing, and flexible billing discount strategies.
Functional Scope
- Table reservations and physical seating occupancy management.
- Digital order capture with customized dishes and dietary instructions.
- Kitchen Display System (KDS) real-time alerts as tickets are submitted.
- Inventory consumption deduction upon cooking dishes.
- Dynamic billing calculation with discounts (Happy Hour, Loyalty points, Corporate).
Entity-Relationship (ER) Schema
Restaurant [1] --> [*] DiningTable Restaurant [1] --> [1] OrderManager Order [1] --> [*] OrderItem Order [1] --> [1] BillingStrategy OrderManager [1] --> [1] KitchenDisplaySystem
Design Approach
Apply the Observer pattern between the OrderManager and Kitchen Display Systems so chefs receive immediate ticket updates. Encapsulate promotional and corporate discounts using the Strategy pattern.
Core Classes & Models
Restaurant (Central system facade)DiningTable (TableId, capacity, TableStatus: FREE, RESERVED, OCCUPIED)Order (OrderId, items, status: PLACED, COOKING, READY, SERVED, PAID)OrderItem (Dish, quantity, special instructions)BillingStrategy (HappyHourStrategy, LoyaltyDiscountStrategy)KitchenDisplaySystem (Observer receiving kitchen tickets)
Code Blueprint
101 lines/**
* Low-Level Design: Restaurant Management System
* Design Patterns Applied:
* - Factory Pattern: Order creation and menu item generation
* - Observer Pattern: Kitchen display system and waiter station notifications
* - Strategy Pattern: Dynamic bill discount and surge pricing strategies
*/
import java.util.*;
enum OrderStatus { PLACED, COOKING, READY, SERVED, PAID }
// --- [DESIGN PATTERN: Strategy] Bill discount strategy ---
interface DiscountStrategy {
double applyDiscount(double subtotal);
}
class HappyHourDiscountStrategy implements DiscountStrategy {
@Override
public double applyDiscount(double subtotal) {
return subtotal * 0.80; // 20% off
}
}
// --- [DESIGN PATTERN: Observer] Kitchen Display System (KDS) observer ---
interface KitchenObserver {
void onNewOrder(int orderId, List<String> dishes);
void onOrderReady(int orderId);
}
class KitchenDisplaySystem implements KitchenObserver {
@Override
public void onNewOrder(int orderId, List<String> dishes) {
System.out.println("👨🍳 [KDS Screen] Order #" + orderId + " received: " + dishes);
}
@Override
public void onOrderReady(int orderId) {
System.out.println("🔔 [KDS Bell] Order #" + orderId + " is READY for pickup!");
}
}
// --- [DESIGN PATTERN: Factory] Meal / Order factory ---
class OrderFactory {
private static int counter = 1000;
public static Order createOrder(int tableNumber, List<String> items) {
return new Order(++counter, tableNumber, items);
}
}
class Order {
private final int id;
private final int tableNumber;
private final List<String> items;
private OrderStatus status = OrderStatus.PLACED;
public Order(int id, int tableNumber, List<String> items) {
this.id = id; this.tableNumber = tableNumber; this.items = items;
}
public int getId() { return id; }
public List<String> getItems() { return items; }
public OrderStatus getStatus() { return status; }
public void setStatus(OrderStatus status) { this.status = status; }
}
class RestaurantManager {
private final List<KitchenObserver> observers = new ArrayList<>();
private final DiscountStrategy discountStrategy;
public RestaurantManager(DiscountStrategy strategy) {
this.discountStrategy = strategy;
}
public void addObserver(KitchenObserver o) { observers.add(o); }
public void submitOrder(Order order) {
for (KitchenObserver o : observers) o.onNewOrder(order.getId(), order.getItems());
}
public void markReady(Order order) {
order.setStatus(OrderStatus.READY);
for (KitchenObserver o : observers) o.onOrderReady(order.getId());
}
public double calculateBill(double subtotal) {
return discountStrategy.applyDiscount(subtotal);
}
}
public class Main {
public static void main(String[] args) {
RestaurantManager manager = new RestaurantManager(new HappyHourDiscountStrategy());
manager.addObserver(new KitchenDisplaySystem());
Order order = OrderFactory.createOrder(4, List.of("Truffle Pasta", "Garlic Bread", "Ginger Ale"));
manager.submitOrder(order);
manager.markReady(order);
double total = manager.calculateBill(50.0);
System.out.printf("Final Bill after discount: $%.2f%n", total);
}
}