Low-Level Design (LLD) of ClearFood in JavaScript

Introduction

ClearFood is a food ordering system where users can order from registered restaurants that serve specific PIN codes. Users can rate restaurants and view serviceable restaurants based on ratings or prices.

Key Features:

  • Users can register and place orders.
  • Restaurants can register and update food quantity.
  • Users can rate restaurants with or without comments.
  • Restaurants are filtered by price or rating.
  • Users can fetch their order history.

Class Design

Restaurant Class

class Restaurant {
  constructor(name, pincodes, foodName, foodPrice, initialQuantity) {
    this.name = name;
    this.pincodes = new Set(pincodes);
    this.foodName = foodName;
    this.foodPrice = foodPrice;
    this.quantity = initialQuantity;
    this.totalRating = 0;
    this.numberOfRatings = 0;
  }

  updateQuantity(quantityToAdd) {
    this.quantity += quantityToAdd;
    console.log(`Updated quantity for ${this.name}: ${this.quantity}`);
  }

  addRating(rating) {
    this.totalRating += rating;
    this.numberOfRatings++;
  }

  getAverageRating() {
    return this.numberOfRatings === 0 ? 0 : this.totalRating / this.numberOfRatings;
  }
}

User Class

class User {
  constructor(name, phoneNumber, pincode) {
    this.name = name;
    this.phoneNumber = phoneNumber;
    this.pincode = pincode;
    this.orders = [];
  }

  placeOrder(restaurant, quantity) {
    if (!restaurant.pincodes.has(this.pincode)) {
      console.log("Restaurant does not deliver to your location.");
      return;
    }
    if (restaurant.quantity < quantity) {
      console.log("Cannot place order. Insufficient quantity.");
      return;
    }
    restaurant.quantity -= quantity;
    this.orders.push({ restaurant: restaurant.name, quantity });
    console.log(`Order placed for ${quantity} ${restaurant.foodName} from ${restaurant.name}`);
  }

  getOrderHistory() {
    return this.orders;
  }

  rateRestaurant(restaurant, rating, comment = "") {
    restaurant.addRating(rating);
    console.log(`Rated ${restaurant.name}: ${rating} stars. Comment: ${comment}`);
  }
}

Helper Functions

class FoodOrderingSystem {
  constructor() {
    this.restaurants = [];
    this.users = [];
  }

  registerRestaurant(name, pincodes, foodName, foodPrice, initialQuantity) {
    let restaurant = new Restaurant(name, pincodes, foodName, foodPrice, initialQuantity);
    this.restaurants.push(restaurant);
    console.log(`Restaurant ${name} registered successfully.`);
  }

  registerUser(name, phoneNumber, pincode) {
    let user = new User(name, phoneNumber, pincode);
    this.users.push(user);
    console.log(`User ${name} registered successfully.`);
  }

  showRestaurants(sortBy) {
    let serviceableRestaurants = this.restaurants.filter(r => r.quantity > 0);
    if (sortBy === "price") {
      serviceableRestaurants.sort((a, b) => a.foodPrice - b.foodPrice);
    } else if (sortBy === "rating") {
      serviceableRestaurants.sort((a, b) => b.getAverageRating() - a.getAverageRating());
    }
    return serviceableRestaurants.map(r => `${r.name}, ${r.foodName} - ${r.foodPrice}`);
  }
}

Simulating the System

const system = new FoodOrderingSystem();

// Register Users
system.registerUser("Pralove", "1234567890", "HSR");
system.registerUser("Nitesh", "0987654321", "BTM");

// Register Restaurants
system.registerRestaurant("Food Court-1", ["BTM", "HSR"], "NI Thali", 100, 5);
system.registerRestaurant("Food Court-2", ["BTM"], "Burger", 120, 3);

// Fetch Restaurants by Price
console.log("Restaurants sorted by price:", system.showRestaurants("price"));

// Place Orders
let user = system.users[0];
let restaurant = system.restaurants[0];
user.placeOrder(restaurant, 2);

// Rate Restaurant
user.rateRestaurant(restaurant, 5, "Amazing food!");

// Fetch Restaurants by Rating
console.log("Restaurants sorted by rating:", system.showRestaurants("rating"));

Conclusion

This implementation follows OOP principles, ensuring encapsulation and modularity. Future improvements can include:

  • Support for multiple food items per restaurant.
  • Database integration instead of in-memory storage.
  • Optimized sorting for large datasets.

This LLD ensures a scalable and maintainable system. 🚀