Bird
Raised Fist0
LLDsystem_design~7 mins

Product, Cart, Order classes in LLD - System Design Guide

Choose your learning style10 modes available

Start learning this pattern below

Jump into concepts and practice - no test required

or
Recommended
Test this pattern10 questions across easy, medium, and hard to know if this pattern is strong
Problem Statement
When designing an e-commerce system, mixing responsibilities of products, shopping carts, and orders in a single class leads to code that is hard to maintain and extend. This causes bugs when updating product details or processing orders, and makes it difficult to add new features like discounts or inventory checks.
Solution
Separate the system into three classes: Product to represent item details, Cart to manage items a user wants to buy, and Order to handle the final purchase process. Each class has clear responsibilities and interacts through well-defined methods, making the system easier to understand, test, and extend.
Architecture
┌─────────┐      ┌─────────┐      ┌─────────┐
│ Product │─────▶│   Cart  │─────▶│  Order  │
└─────────┘      └─────────┘      └─────────┘
     ▲               │               │
     │               │               │
     └───────────────┴───────────────┘

This diagram shows the flow where Product instances are added to the Cart, and the Cart is then used to create an Order.

Trade-offs
✓ Pros
Clear separation of concerns improves code maintainability.
Easier to add features like discounts or inventory management in specific classes.
Simplifies testing by isolating functionality.
Improves readability and collaboration among developers.
✗ Cons
Requires more upfront design and planning.
May introduce more classes and interfaces, increasing initial complexity.
Inter-class communication needs careful design to avoid tight coupling.
Use when building any e-commerce or shopping system with multiple products and user carts, especially if the system expects growth or feature additions.
Avoid if building a very simple prototype or script with minimal features where separation adds unnecessary complexity.
Real World Examples
Amazon
Separates product catalog management, user shopping carts, and order processing to handle millions of users and complex purchase flows.
Shopify
Uses distinct classes for products, carts, and orders to allow merchants to customize each part independently.
Uber Eats
Manages menu items as products, user selections as carts, and final orders separately to support real-time updates and order tracking.
Code Example
The before code mixes product storage, cart management, and checkout in one class, making it hard to maintain. The after code separates these concerns into Product, Cart, and Order classes, each with clear responsibilities and interactions.
LLD
### Before: All logic in one class (bad design)
class ECommerce:
    def __init__(self):
        self.products = {}
        self.cart = {}

    def add_product(self, product_id, name, price):
        self.products[product_id] = {'name': name, 'price': price}

    def add_to_cart(self, product_id, quantity):
        if product_id in self.products:
            self.cart[product_id] = self.cart.get(product_id, 0) + quantity

    def checkout(self):
        total = 0
        for pid, qty in self.cart.items():
            total += self.products[pid]['price'] * qty
        self.cart.clear()
        return total


### After: Separate Product, Cart, and Order classes (good design)
class Product:
    def __init__(self, product_id: int, name: str, price: float):
        self.product_id = product_id
        self.name = name
        self.price = price

class Cart:
    def __init__(self):
        self.items = {}  # product_id -> quantity

    def add_product(self, product: Product, quantity: int):
        self.items[product.product_id] = self.items.get(product.product_id, 0) + quantity

    def get_total(self, product_catalog: dict) -> float:
        total = 0
        for pid, qty in self.items.items():
            total += product_catalog[pid].price * qty
        return total

    def clear(self):
        self.items.clear()

class Order:
    def __init__(self, cart: Cart, product_catalog: dict):
        self.cart = cart
        self.product_catalog = product_catalog
        self.total_amount = 0
        self.is_paid = False

    def place_order(self):
        self.total_amount = self.cart.get_total(self.product_catalog)
        self.is_paid = True  # Simplified
        self.cart.clear()
        return self.total_amount
OutputSuccess
Alternatives
Monolithic class
Combines product, cart, and order logic into one class without separation.
Use when: Only for very simple applications or quick prototypes with no plans for scaling.
Microservices
Splits product, cart, and order into separate services communicating over network calls.
Use when: For large-scale distributed systems requiring independent deployment and scaling.
Summary
Separating Product, Cart, and Order into distinct classes improves code clarity and maintainability.
Each class has a focused responsibility, making it easier to add features and fix bugs.
This design pattern is essential for scalable and extensible e-commerce systems.

Practice

(1/5)
1. Which class is responsible for storing the details like product ID, name, and price?
easy
A. Product class
B. Cart class
C. Order class
D. User class

Solution

  1. Step 1: Understand the role of Product class

    The Product class stores item details such as ID, name, and price.
  2. Step 2: Compare with other classes

    The Cart class holds selected products and quantities, and Order class records purchased items and status, not product details.
  3. Final Answer:

    Product class -> Option A
  4. Quick Check:

    Product details = Product class [OK]
Hint: Product details belong to Product class only [OK]
Common Mistakes:
  • Confusing Cart with Product class
  • Thinking Order stores product details
  • Assuming User class stores product info
2. Which of the following is the correct way to add a product to a cart in a typical class design?
easy
A. order.addProduct(product, quantity)
B. product.addToCart(cart, quantity)
C. cart.addProduct(product, quantity)
D. cart.createOrder(product, quantity)

Solution

  1. Step 1: Identify the class responsible for holding selected products

    The Cart class holds selected products and their quantities before purchase.
  2. Step 2: Check method naming conventions

    Adding a product to a cart is typically done by calling a method on the Cart object, like addProduct(product, quantity).
  3. Final Answer:

    cart.addProduct(product, quantity) -> Option C
  4. Quick Check:

    Adding product to cart = cart.addProduct() [OK]
Hint: Add products via Cart methods, not Product or Order [OK]
Common Mistakes:
  • Calling addToCart on Product class
  • Using Order class to add products before purchase
  • Confusing method names like createOrder in Cart
3. Given the following code snippet, what will be the total cost stored in the Order after checkout?
product1 = Product(id=1, name='Pen', price=2)
product2 = Product(id=2, name='Notebook', price=5)
cart = Cart()
cart.addProduct(product1, 3)
cart.addProduct(product2, 2)
order = Order(cart)
order.checkout()
medium
A. 16
B. 19
C. 10
D. 7

Solution

  1. Step 1: Calculate total cost from cart products and quantities

    Pen price = 2, quantity = 3 -> 2 * 3 = 6
    Notebook price = 5, quantity = 2 -> 5 * 2 = 10
    Total = 6 + 10 = 16
  2. Step 2: Check if any additional charges or taxes apply

    No extra charges mentioned, so total cost should be 16.
  3. Final Answer:

    16 -> Option A
  4. Quick Check:

    2*3 + 5*2 = 16 [OK]
Hint: Multiply price by quantity, then sum all products [OK]
Common Mistakes:
  • Adding quantities instead of multiplying by price
  • Mixing product prices and quantities incorrectly
  • Ignoring one product's cost
4. Identify the error in this Order class method that calculates total cost:
class Order:
def __init__(self, cart):
self.cart = cart
self.total = 0
def calculate_total(self):
for product, qty in self.cart.items():
self.total += product.price * qty
return self.total
medium
A. Returning total instead of printing it
B. Using self.cart.items() instead of self.cart.products.items()
C. Multiplying price by quantity incorrectly
D. Not resetting self.total before calculation

Solution

  1. Step 1: Analyze total calculation logic

    The method adds product price times quantity to self.total in a loop.
  2. Step 2: Check for accumulation errors

    Since self.total is not reset before calculation, repeated calls will add to previous total, causing incorrect sums.
  3. Final Answer:

    Not resetting self.total before calculation -> Option D
  4. Quick Check:

    Reset total before sum to avoid accumulation [OK]
Hint: Reset totals before summing to avoid repeated addition errors [OK]
Common Mistakes:
  • Assuming cart.items() is invalid without context
  • Thinking multiplication is wrong when it is correct
  • Confusing return with print for output
5. You want to design a system where a Cart can hold multiple Products with quantities, and an Order records the purchased items and status. Which design choice best supports scalability and clear responsibility?
hard
A. Make Cart store product IDs only; Order stores full product details and quantities
B. Make Cart hold Product objects with quantities; Order copies Cart items and tracks status separately
C. Make Product class hold quantity and add methods to update Cart and Order directly
D. Make Order class inherit from Cart and add status and total cost fields

Solution

  1. Step 1: Understand separation of concerns

    Cart should hold selected products and quantities before purchase. Order should record purchased items and status separately.
  2. Step 2: Evaluate design options for scalability and clarity

    Make Cart hold Product objects with quantities; Order copies Cart items and tracks status separately keeps Cart holding Product objects with quantities, and Order copies these items to keep a snapshot and track status, which is clean and scalable.
  3. Final Answer:

    Make Cart hold Product objects with quantities; Order copies Cart items and tracks status separately -> Option B
  4. Quick Check:

    Separate Cart and Order responsibilities for scalability [OK]
Hint: Keep Cart and Order responsibilities separate and clear [OK]
Common Mistakes:
  • Making Order inherit Cart causing tight coupling
  • Storing only product IDs in Cart losing details
  • Putting quantity in Product class mixing concerns