Bird
Raised Fist0

Design an Online Shopping Cart - Product, Cart, Order, Discount, Coupon OOP

LLDmediumInterview freq: high
Choose your preparation mode4 modes available
🏗️
Design an Online Shopping Cart - Product, Cart, Order, Discount, Coupon OOP
Design a scalable and extensible online shopping cart system with product catalog, cart management, order processing, and discount application.
mediumFinancial and E-Commerce OOPFreq: high
Prerequisites:OOP FundamentalsJava concurrency basicsDesign patterns (Strategy, Factory, Observer)SOLID principles
⚙️
Functional Requirements
  • Support adding multiple products with quantities to cart
  • Apply multiple discount types (percentage, fixed amount) and coupons
  • Calculate total price dynamically reflecting discounts and taxes
  • Prevent overselling by validating inventory at order time
  • Allow order cancellation and refund processing
  • Persist cart state for logged-in customers
  • Support concurrency for multiple simultaneous cart updates
👤
Use Cases
  • Customer adds/removes products to/from cart
  • Customer applies coupons or discounts to cart
  • Customer places an order from the cart
  • System validates product availability during order placement
  • System calculates final price with discounts and coupons
  • System updates inventory after order confirmation
🧑‍💻
Actors
  • Customer
  • System Administrator
  • Payment Gateway
  • Inventory System
❓
Clarifying Questions to Ask
  • How many concurrent users/threads can update the same cart simultaneously?
  • Are discounts stackable or mutually exclusive?
  • Should coupons have usage limits or expiration dates?
  • What pricing strategy applies when multiple discounts overlap?
  • How to handle product inventory changes during order placement?
  • Is cart persistence required for guest users or only logged-in users?
Out of Scope
✗ Payment processing internals
✗ User authentication and authorization
✗ Shipping and delivery management
✗ Product catalog management beyond basic attributes
⚡
QPS Calculation
read qps10000
write qps2000
🖥️
Server Estimate
app servers10
db servers3
cache servers2
Estimates based on expected user base, concurrency, and data size to ensure scalability.
🔢
Enumerations
enum ProductCategory
ELECTRONICS | CLOTHING | BOOKS | HOME_APPLIANCES | TOYS
Enum prevents typo bugs and enables exhaustive switch statements for category-specific logic.
enum OrderStatus
PENDING | CONFIRMED | SHIPPED | DELIVERED | CANCELLED | REFUNDED
Defines finite order lifecycle states, enabling clear state transitions and validation.
enum DiscountType
PERCENTAGE | FIXED_AMOUNT | BUY_ONE_GET_ONE
Encapsulates discount calculation strategies and prevents invalid discount type usage.
enum CouponStatus
ACTIVE | EXPIRED | USED | INVALID
Tracks coupon validity and usage state to enforce business rules.
📦
Product
5 fields
private final String productIdprivate final String nameprivate final ProductCategory categoryprivate final double priceprivate volatile int availableQuantity
Represents a product with immutable identity and mutable inventory quantity. Provides thread-safe inventory updates.
public synchronized boolean decrementInventory(int quantity)Atomically decreases availableQuantity if sufficient stock exists; returns success status.
public synchronized void incrementInventory(int quantity)Atomically increases availableQuantity.
public double getPrice()Returns the product price.
📦
CartItem
2 fields
private final Product productprivate int quantity
Holds a product and its quantity in the cart. Manages quantity updates.
public synchronized void updateQuantity(int quantity)Updates the quantity of the product in the cart atomically.
public double getTotalPrice()Calculates total price for this item (product price * quantity).
📦
Cart
4 fields
private final String cartIdprivate final Map<String, CartItem> itemsprivate final List<Discount> discountsprivate final List<Coupon> coupons
Manages cart items, discounts, and coupons. Calculates total price with applied discounts and coupons. Thread-safe updates to items and discounts.
public synchronized void addProduct(Product product, int quantity)Adds product to cart or updates quantity if already present.
public synchronized void removeProduct(String productId)Removes product from cart.
public synchronized void applyDiscount(Discount discount)Adds a discount to the cart.
public synchronized boolean applyCoupon(Coupon coupon)Attempts to apply a coupon; returns true if successful.
public synchronized double calculateTotalPrice()Calculates total price after applying discounts and coupons.
📦
Order
5 fields
private final String orderIdprivate final Cart cartprivate volatile OrderStatus statusprivate final Date orderDateprivate final double finalPrice
Represents a finalized order with immutable cart snapshot and status. Manages order lifecycle states with thread-safe status updates.
public synchronized boolean confirmOrder()Validates inventory and confirms order atomically; returns success.
public synchronized void cancelOrder()Cancels order and triggers inventory rollback.
public OrderStatus getStatus()Returns current order status.
📦
Discount
3 fields
private final String discountIdprivate final DiscountType typeprivate final double value
Abstract discount entity defining discount type and value. Provides discount calculation interface.
public abstract double calculateDiscountAmount(double totalPrice)Calculates discount amount based on total price.
📦
PercentageDiscount
1 fields
inherits Discount
Concrete discount applying percentage off total price.
public double calculateDiscountAmount(double totalPrice)Returns totalPrice * value / 100.
📦
Coupon
5 fields
private final String couponCodeprivate final CouponStatus statusprivate final Date expiryDateprivate final int usageLimitprivate int usageCount
Represents a coupon with code, status, expiry, and usage limits. Validates applicability and usage.
public synchronized boolean isValid()Checks if coupon is active, not expired, and usage limit not exceeded.
public synchronized boolean applyCoupon()Increments usage count if valid and marks coupon as used if limit reached.
🔗
Relationships
Cart◆──►CartItem[1..*]
compositionCart owns CartItems; deleting Cart deletes CartItems
CartItem──►Product[1]
associationCartItem references Product; Product lifecycle independent
Order◇──►Cart[1]
aggregationOrder references Cart snapshot; Cart can exist independently
Discount──►Cart[0..*]
associationDiscounts applied to Cart; Discounts exist independently
Coupon──►Cart[0..*]
associationCoupons applied to Cart; Coupons exist independently
PercentageDiscount──►Discount[1]
inheritancePercentageDiscount is a subtype of Discount
🗄️
Products
PK: productId
productId STRINGname STRINGcategory STRINGprice DOUBLEavailableQuantity INT
Stores product catalog with inventory.
🗄️
Orders
PK: orderId
orderId STRINGcartId STRINGstatus STRINGorderDate TIMESTAMPfinalPrice DOUBLE
Stores order details and status.
🔌
POST
AddProductToCart
Request
{
  "productId": "string",
  "quantity": "int"
}
Response
{
  "success": "boolean",
  "message": "string"
}
Adds or updates product quantity in the cart.
🔌
POST
ApplyCouponToCart
Request
{
  "couponCode": "string"
}
Response
{
  "success": "boolean",
  "message": "string"
}
Applies a coupon to the cart if valid.
🔌
POST
PlaceOrder
Request
{
  "cartId": "string"
}
Response
{
  "orderId": "string",
  "status": "string",
  "finalPrice": "double"
}
Places an order from the cart after validation.

Practice

(1/5)
1. In designing the Piece abstraction for the Jigsaw Puzzle System, should Piece be an abstract class or an interface? Consider that each piece has state (shape, edges) and behavior (fit check). Which is the best choice and why?
easy
A. Piece should be an interface because it only defines behavior, and state should be in implementations.
B. Piece should be an abstract class because it holds common state and default behavior for all pieces.
C. Piece should be a concrete class to allow direct instantiation and avoid subclassing complexity.
D. Piece should be a static utility class since pieces only need stateless helper methods.

Solution

  1. Step 1: Analyze state and behavior requirements

    Pieces share common state (shape, edges) and behavior (fit check), so code reuse and shared state management is needed.
  2. Step 2: Evaluate abstract class vs interface

    Abstract class allows holding common state and default behavior, while interface cannot hold state (pre-Java 8) and only defines contracts.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Abstract class holds shared state and behavior for Pieces [check]
Hint: State + behavior = abstract class, not interface [check]
Common Mistakes:
2. You want to add a WeekendFeeStrategy to calculate parking fees differently on weekends using the current adapter-based design. What is the minimum change required to comply with SOLID principles?
medium
A. Add a boolean flag to Vehicle to indicate weekend and modify ParkingLot to check it.
B. Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it where needed without modifying existing classes.
C. Modify the existing FeeStrategy class to add weekend logic with if-else checks.
D. Add weekend fee logic inside the adapter class that adapts Vehicle to ParkingLot.

Solution

  1. Step 1: Identify SOLID principle involved

    Open-Closed Principle (OCP) requires extending behavior without modifying existing code.
  2. Step 2: Evaluate options

    Create a new WeekendFeeStrategy class implementing FeeStrategy and inject it where needed without modifying existing classes. respects OCP by adding a new class implementing FeeStrategy. Add a boolean flag to Vehicle to indicate weekend and modify ParkingLot to check it. modifies Vehicle and ParkingLot, violating OCP. Options A and D modify existing classes.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    New strategy class extends behavior without modifying existing code [check]
Hint: OCP: extend with new class, don't modify existing ones [check]
Common Mistakes:
3. In the Library Management System, the reserveBook() method is not synchronized. Which exact sequence of Thread 1 and Thread 2 calls causes double reservation of the same book copy?
medium
A. Thread 1 checks availability -> true, context switch; Thread 2 checks availability -> true; both reserve simultaneously.
B. Thread 1 reserves, then Thread 2 checks availability -> false and aborts.
C. Thread 1 calls reserveBook(), Thread 2 waits until Thread 1 finishes, then reserves.
D. Thread 1 and Thread 2 both wait on a lock, so no double reservation occurs.

Solution

  1. Step 1: Identify the check-then-act race condition

    Without synchronization, both threads can read availability as true before either updates the reservation status.
  2. Step 2: Trace thread interleaving causing double booking

    Thread 1 reads available=true, context switch; Thread 2 reads available=true; both proceed to reserve, causing double booking.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Unsynchronized check-then-act -> both see available=true -> double reservation [check]
Hint: Check availability -> context switch -> both reserve -> double booking [check]
Common Mistakes:
4. In the auction system, the placeBid() method checks if the auction is still open before accepting a bid. Without synchronizing placeBid(), which exact thread interleaving causes two threads to accept bids after the auction closes, resulting in inconsistent state?
medium
A. Thread 1 reads auction open -> false; Thread 2 reads auction open -> true; both reject bids.
B. Thread 1 and Thread 2 both wait on a lock; no bids accepted until lock released.
C. Thread 1 writes bid; Thread 2 reads bid; no race condition occurs because writes are atomic.
D. Thread 1 reads auction open -> true; context switch before bid recorded; Thread 2 reads auction open -> true; both record bids after auction closed.

Solution

  1. Step 1: Identify check-then-act race

    Without synchronization, Thread 1 reads auction open as true but is preempted before recording the bid.
  2. Step 2: Thread 2 reads auction open as true and proceeds to record bid as well, both bypassing the closed state check.

  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Unsynchronized check-then-act -> double acceptance after close [check]
Hint: Check-then-act without sync -> race condition double accept [check]
Common Mistakes:
5. The current Facebook design uses a PrivacyStrategy interface for post visibility. To add a WeekendPrivacyStrategy that restricts posts only on weekends, what is the minimum change required to comply with SOLID principles?
medium
A. Modify the existing PrivacyStrategy implementations to add weekend checks.
B. Create a new WeekendPrivacyStrategy class implementing PrivacyStrategy without changing existing classes.
C. Add a boolean flag isWeekend in the base Post class and check it in all privacy methods.
D. Combine all privacy logic into a single class with conditional weekend logic.

Solution

  1. Step 1: Identify applicable SOLID principle

    Open/Closed Principle (OCP) requires extending behavior without modifying existing code.
  2. Step 2: Apply OCP to privacy strategies

    Adding a new class implementing PrivacyStrategy extends functionality without changing existing classes.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    New class for new behavior -> OCP compliance [check]
Hint: OCP: extend with new class, don't modify existing [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