Skip to main content

Design a Online Bookstore System

Problem Statement

Design an online bookstore system that allows users to browse books, search by title or category, add books to a cart, and place orders. The system should handle inventory management, ensure books are available before purchase, and maintain order history for users.


Functional Requirements

  • Users should be able to browse all available books
  • Users should be able to search books by title or author
  • Users can add or remove books from cart
  • Users can place an order for items in the cart
  • System should check inventory before confirming order
  • Each order should maintain order history

Objects Required

  • Book
  • User
  • Cart
  • CartItem
  • Order
  • Inventory
  • BookStoreService

Book Class


public class Book {

    private String bookId;
    private String title;
    private String author;
    private double price;

    public Book(String bookId, String title, String author, double price) {
        this.bookId = bookId;
        this.title = title;
        this.author = author;
        this.price = price;
    }

    public String getTitle() {
        return title;
    }

    public double getPrice() {
        return price;
    }
}

The constructor initializes a book with its unique id, title, author, and price so it can be uniquely identified and displayed in the store.

The getTitle() method returns the book title when the system needs to display or search books without exposing internal fields.

The getPrice() method provides controlled access to pricing information used during cart calculation and order processing.


CartItem Class


public class CartItem {

    private Book book;
    private int quantity;

    public CartItem(Book book, int quantity) {
        this.book = book;
        this.quantity = quantity;
    }

    public double getTotalPrice() {
        return book.getPrice() * quantity;
    }
}

The constructor links a book with a selected quantity so that each cart entry represents a real purchase intent.

The getTotalPrice() method calculates the total cost of this cart item by multiplying book price with quantity, ensuring cart totals stay consistent and centralized.


Cart Class


import java.util.*;

public class Cart {

    private List items = new ArrayList<>();

    public void addItem(Book book, int qty) {
        items.add(new CartItem(book, qty));
    }

    public void removeItem(Book book) {
        items.removeIf(item -> item.getTotalPrice() == book.getPrice());
    }

    public List getItems() {
        return items;
    }

    public double getCartTotal() {
        double total = 0;
        for (CartItem item : items) {
            total += item.getTotalPrice();
        }
        return total;
    }
}

The constructor initializes an empty cart ready to accept items.

The addItem() method adds a book with a specified quantity into the cart. It encapsulates cart item creation so the caller doesn’t manage internal structure.

The removeItem() method removes a book from the cart if the user changes their mind before checkout.

The getCartTotal() method calculates the final amount by aggregating all cart items, ensuring pricing logic stays inside the cart itself.


Inventory Class


import java.util.*;

public class Inventory {

    private Map stock = new HashMap<>();

    public boolean isAvailable(String bookId, int qty) {
        return stock.getOrDefault(bookId, 0) >= qty;
    }

    public void reduceStock(String bookId, int qty) {
        stock.put(bookId, stock.get(bookId) - qty);
    }

    public void addStock(String bookId, int qty) {
        stock.put(bookId, stock.getOrDefault(bookId, 0) + qty);
    }
}

The inventory class manages stock levels for each book using a map for quick lookup.

The isAvailable() method ensures a book has enough stock before allowing an order to proceed, preventing overselling.

The reduceStock() method decreases inventory after a successful order, keeping stock synchronized.

The addStock() method allows restocking when new inventory arrives from publishers or sellers.


Order Class


import java.util.*;

public class Order {

    private String orderId;
    private List items;
    private double totalAmount;

    public Order(String orderId, List items, double totalAmount) {
        this.orderId = orderId;
        this.items = items;
        this.totalAmount = totalAmount;
    }

    public double getTotalAmount() {
        return totalAmount;
    }
}

The constructor creates an order once checkout is successful and stores purchased items along with final billing amount.

The getTotalAmount() method returns the final payable amount, which is already calculated at checkout time to avoid recalculation inconsistencies.


BookStoreService Class


import java.util.*;

public class BookStoreService {

    private Inventory inventory;

    public BookStoreService(Inventory inventory) {
        this.inventory = inventory;
    }

    public Order placeOrder(String orderId, Cart cart) {

        for (CartItem item : cart.getItems()) {
            if (!inventory.isAvailable(item.getBook().getTitle(), 1)) {
                System.out.println("Book not available: " + item.getBook().getTitle());
                return null;
            }
        }

        for (CartItem item : cart.getItems()) {
            inventory.reduceStock(item.getBook().getTitle(), 1);
        }

        return new Order(orderId, cart.getItems(), cart.getCartTotal());
    }
}

The constructor injects inventory dependency so that stock validation and updates remain centralized.

The placeOrder() method first validates if all requested books are available in sufficient quantity. If even one book is unavailable, the entire order is rejected to maintain consistency.

After validation, stock is reduced and a final order object is created, representing a successful checkout.


User Class


public class User {

    private String userId;
    private String name;

    public User(String userId, String name) {
        this.userId = userId;
        this.name = name;
    }
}

The User class represents a customer in the system who can browse books, manage a cart, and place orders.


Main Class


public class Main {

    public static void main(String[] args) {

        Inventory inventory = new Inventory();
        inventory.addStock("B1", 10);

        Book book = new Book("B1", "Clean Code", "Robert C. Martin", 500);

        Cart cart = new Cart();
        cart.addItem(book, 2);

        User user = new User("U1", "Prasanna");

        BookStoreService service = new BookStoreService(inventory);

        Order order = service.placeOrder("O1", cart);

        if (order != null) {
            System.out.println("Order placed successfully. Total: " + order.getTotalAmount());
        }
    }
}

The main method simulates a full bookstore flow starting from adding inventory to successfully placing an order.

It demonstrates how cart validation, inventory checking, and order creation work together in a real system.


Class Diagram

BookbookId : Stringtitle : Stringauthor : Stringprice : doublegetTitle() : StringgetPrice() : doubleUseruserId : Stringname : StringCartitems : List<CartItem>addItem(book, qty) : voidremoveItem(book) : voidgetCartTotal() : doubleCartItembook : Bookquantity : intgetTotalPrice() : doubleInventoryisAvailable(bookId, qty) : booleanreduceStock(bookId, qty) : voidaddStock(bookId, qty) : voidOrderorderId : Stringitems : List<CartItem>totalAmount : doublegetTotalAmount() : doubleBookStoreServiceplaceOrder(orderId, cart) : OrderMainmain(args : String[]) : void

Also See

Comments

Popular posts from this blog

Designing a Parking Lot - Low Level Design

Problem Statement Design a parking lot that can handle vehicles entering and leaving while managing parking across multiple floors. Each vehicle should be assigned a suitable parking spot based on its type, and the spot should be freed once the vehicle exits. The design should also support generating a ticket at entry and optionally calculating the parking fee based on the duration of stay. Asked In Companies Amazon Google Microsoft Uber Walmart Flipkart Meta PayPal Oracle Salesforce Adobe Apple Intuit LinkedIn Atlassian Functional Requirements The design should support multiple vehicle types such as bikes, cars, and trucks A vehicle must be assigned a parking spot compatible with its type A parking spot cannot be assigned to more than one vehicle at a time The parking lot should support multiple levels (floors) The design should search and allocate an availa...

Most Frequently Asked Low Level Design(LLD) Interview Questions

Below are the curated list of most commonly asked Low Level Design (LLD) interview problems. Each problem includes a short description and a link to the complete solution with code and class diagrams. Design Parking Lot System The system should handle parking for different vehicle types such as bikes, cars, and trucks. It should manage slot allocation, availability tracking, and entry/exit flow. The design also ensures efficient usage of parking space under varying load conditions. View Solution Design Elevator / Lift System The system should support multiple elevators operating across floors with request handling logic. It focuses on scheduling algorithms to minimize wait time and optimize movement. It also manages direction control and concurrent floor requests. View Solution Design Movie Ticket Booking System The system should allow users to browse movies, select shows, and book seats. It handles seat ...

Software Design Patterns for LLD Interviews: A Complete Guide

Software Design Patterns for LLD Interviews: A Complete Guide In Software Development Engineer (SDE) interviews—especially for mid-level and senior roles—low-level design (LLD) rounds assess your ability to write clean, reusable, maintainable, and extensible code. The foundation of resolving these architectural challenges lies in the standard Gang of Four (GoF) Design Patterns. Rather than memorizing theoretical definitions, interviewers expect you to apply these patterns to real-world scenarios, identifying the trade-offs of each. Below is a comprehensive guide to the 12 most frequently asked design patterns in LLD interviews, categorized by their classification (Creational, Structural, and Behavioral). Each pattern contains a concrete, real-world Java implementation and a detailed breakdown of design decisions. Creational Design Patterns Creational design patterns deal with object creation mechanisms. They abstract the instantiation process, making a system independent of how...