Amazon - Online Shopping System
Amazon (amazon.com) is the world’s largest online retailer. The company was originally a bookseller but has expanded to sell a wide variety of consumer goods and digital media. For the sake of this problem, we will focus on their online retail business where users can sell/buy their products.
Features
We will be designing a system with the following requirements:
Users should be able to add new products to sell.
Users should be able to search for products by their name or category.
Users can search and view all the products, but they will have to become a registered member to buy a product.
Users should be able to add/remove/modify product items in their shopping cart.
Users can check out and buy items in the shopping cart.
Users can rate and add a review for a product.
The user should be able to specify a shipping address where their order will be delivered.
Users can cancel an order if it has not shipped.
Users should get notifications whenever there is a change in the order or shipping status.
Users should be able to pay through credit cards or electronic bank transfer.
Users should be able to track their shipment to see the current state of their order.
Rough Solution (LLD-Machine Coding)
Patterns:
// Enums
// Represents different order statuses with additional states for handling errors and returns
public enum OrderStatus {
UNSHIPPED,
PENDING,
SHIPPED,
COMPLETED,
CANCELED,
RETURN_REQUESTED,
RETURNED,
REFUND_APPLIED,
ERROR // This status can handle unexpected issues in the order processing flow
}
// Represents different account statuses with more granular control over the state of an account
public enum AccountStatus {
ACTIVE,
BLOCKED,
BANNED,
COMPROMISED,
ARCHIVED,
CLOSED,
UNKNOWN
}
// Represents various stages of shipment status to ensure transparency in shipping
public enum ShipmentStatus {
PENDING,
SHIPPED,
IN_TRANSIT,
DELIVERED,
DELAYED,
ON_HOLD,
OUT_FOR_DELIVERY,
LOST, // Handle cases where a shipment might go missing
RETURNED // If a customer returns the product, we can track that in the shipment
}
// Payment status with additional scenarios for better handling of real-world payment outcomes
public enum PaymentStatus {
UNPAID,
PENDING,
COMPLETED,
FAILED, // For cases where payment fails due to technical or financial issues
DECLINED, // When payment is declined (e.g., insufficient funds or fraud detection)
CANCELLED,
REFUNDED, // To handle cases where a refund has been issued
DISPUTED, // In case of chargebacks or disputes raised by customers
ABANDONED, // For abandoned payment processes (e.g., customer left the checkout)
SETTLING, // Intermediate state when the payment is being processed by the gateway
SETTLED
}
// Enum for different roles or access levels in the system
public enum UserRole {
ADMIN, // Full access to account, product, and system settings
GUEST, // Limited access, primarily for browsing and cart management
MEMBER, // Registered users with full shopping functionalities (e.g., order, wishlist)
SELLER, // For users selling their own products
CUSTOMER_SERVICE // Users who manage support and inquiries
}
// Enum for different product categories, used for product classification and catalog searches
public enum ProductCategoryType {
ELECTRONICS,
BOOKS,
CLOTHING,
HOME_APPLIANCES,
SPORTS,
BEAUTY_AND_HEALTH,
FURNITURE,
TOYS_AND_GAMES,
FOOD_AND_GROCERY,
AUTOMOTIVE,
OFFICE_SUPPLIES,
OTHER // For products that don't fit neatly into any other category
}
// Enum for various notification types in the system to manage different alerts and messages
public enum NotificationType {
ORDER_CONFIRMATION, // Notification sent when an order is confirmed
SHIPMENT_UPDATE, // For any shipment updates (shipped, in transit, delivered, etc.)
PAYMENT_FAILURE, // If payment fails
PROMOTIONAL, // For sending promotions or discount alerts
SYSTEM_ALERT, // System-related notifications (e.g., maintenance)
ACCOUNT_STATUS_UPDATE, // When account status changes (e.g., blocked or compromised)
REFUND_STATUS // When a refund is processed
}
// Supporting classes for Address and other details
public class Address {
private String streetAddress;
private String city;
private String state;
private String zipCode;
private String country;
}
// Factory Method Pattern for creating accounts, products, and orders
abstract class AccountFactory {
public abstract Account createAccount(String userName, String password, String name, Address address);
}
class GuestFactory extends AccountFactory {
@Override
public GuestAccount createAccount(String userName, String password, String name, Address address) {
return new GuestAccount(userName, password, name, address);
}
}
class MemberFactory extends AccountFactory {
@Override
public Member createAccount(String userName, String password, String name, Address address) {
return new Member(userName, password, name, address);
}
}
// Command Pattern for handling cart actions and placing orders
interface Command {
void execute();
}
class AddItemToCartCommand implements Command {
private ShoppingCart cart;
private Item item;
public AddItemToCartCommand(ShoppingCart cart, Item item) {
this.cart = cart;
this.item = item;
}
@Override
public void execute() {
cart.addItem(item);
}
}
class RemoveItemFromCartCommand implements Command {
private ShoppingCart cart;
private Item item;
public RemoveItemFromCartCommand(ShoppingCart cart, Item item) {
this.cart = cart;
this.item = item;
}
@Override
public void execute() {
cart.removeItem(item);
}
}
class PlaceOrderCommand implements Command {
private Member member;
private Order order;
public PlaceOrderCommand(Member member, Order order) {
this.member = member;
this.order = order;
}
@Override
public void execute() {
member.placeOrder(order);
}
}
// Observer Pattern for notifications
interface Observer {
void update(String message);
}
class Member implements Observer {
private Account account;
public Member(String userName, String password, String name, Address address) {
account = new Account(userName, password, name, address);
}
@Override
public void update(String message) {
System.out.println("Notification for Member: " + account.getName() + ": " + message);
}
public OrderStatus placeOrder(Order order) {
// Implement logic for placing an order
System.out.println("Order placed successfully.");
return OrderStatus.PENDING;
}
}
class SystemNotifier {
private List<Observer> observers = new ArrayList<>();
public void addObserver(Observer observer) {
observers.add(observer);
}
public void removeObserver(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
// Strategy Pattern for payment methods
interface PaymentStrategy {
void pay(Payment payment);
}
class CreditCardPaymentStrategy implements PaymentStrategy {
@Override
public void pay(Payment payment) {
System.out.println("Processing credit card payment...");
payment.processPayment();
}
}
class BankTransferPaymentStrategy implements PaymentStrategy {
@Override
public void pay(Payment payment) {
System.out.println("Processing bank transfer payment...");
payment.processPayment();
}
}
// Template Method Pattern for Order Processing
abstract class Payment {
protected double amount;
protected PaymentStatus status;
public final void processPayment() {
initiatePayment();
confirmPayment();
updatePaymentStatus();
}
protected abstract void initiatePayment();
private void confirmPayment() {
System.out.println("Payment confirmed.");
}
private void updatePaymentStatus() {
this.status = PaymentStatus.COMPLETED;
System.out.println("Payment status updated to COMPLETED.");
}
}
class CreditCardPayment extends Payment {
@Override
protected void initiatePayment() {
System.out.println("Initiating credit card payment of amount: " + amount);
}
}
class BankTransferPayment extends Payment {
@Override
protected void initiatePayment() {
System.out.println("Initiating bank transfer payment of amount: " + amount);
}
}
// Main classes for customer, orders, and products
public class Account {
private String userName;
private String password;
private AccountStatus status;
private String name;
private Address shippingAddress;
private String email;
private String phone;
private List<CreditCard> creditCards;
private List<ElectronicBankTransfer> bankAccounts;
public Account(String userName, String password, String name, Address shippingAddress) {
this.userName = userName;
this.password = password;
this.name = name;
this.shippingAddress = shippingAddress;
this.status = AccountStatus.ACTIVE;
}
public String getName() {
return name;
}
}
public abstract class Customer {
private ShoppingCart cart;
private Order order;
public ShoppingCart getShoppingCart() {
return cart;
}
public boolean addItemToCart(Item item) {
return cart.addItem(item);
}
public boolean removeItemFromCart(Item item) {
return cart.removeItem(item);
}
}
public class GuestAccount extends Account {
public GuestAccount(String userName, String password, String name, Address address) {
super(userName, password, name, address);
}
public boolean registerAccount() {
// Logic for guest to register an account
return true;
}
}
public class Product {
private String productID;
private String name;
private String description;
private double price;
private ProductCategory category;
private int availableItemCount;
private Account seller;
public Product(String productID, String name, String description, double price, ProductCategory category, Account seller) {
this.productID = productID;
this.name = name;
this.description = description;
this.price = price;
this.category = category;
this.seller = seller;
this.availableItemCount = 0;
}
public int getAvailableCount() {
return availableItemCount;
}
public boolean updatePrice(double newPrice) {
this.price = newPrice;
System.out.println("Price updated to: " + newPrice);
return true;
}
}
public class Item {
private String productID;
private int quantity;
private double price;
public Item(String productID, int quantity, double price) {
this.productID = productID;
this.quantity = quantity;
this.price = price;
}
public boolean updateQuantity(int quantity) {
this.quantity = quantity;
System.out.println("Quantity updated to: " + quantity);
return true;
}
}
public class ShoppingCart {
private List<Item> items;
public ShoppingCart() {
items = new ArrayList<>();
}
public boolean addItem(Item item) {
items.add(item);
System.out.println("Item added to cart.");
return true;
}
public boolean removeItem(Item item) {
items.remove(item);
System.out.println("Item removed from cart.");
return true;
}
public List<Item> getItems() {
return items;
}
public boolean checkout() {
// Implement checkout process
System.out.println("Checkout completed.");
return true;
}
}
public class Order {
private String orderNumber;
private OrderStatus status;
private Date orderDate;
private List<OrderLog> orderLog;
public Order(String orderNumber) {
this.orderNumber = orderNumber;
this.status = OrderStatus.UNSHIPPED;
this.orderDate = new Date();
this.orderLog = new ArrayList<>();
}
public boolean sendForShipment() {
// Logic for sending order for shipment
this.status = OrderStatus.SHIPPED;
System.out.println("Order sent for shipment.");
return true;
}
public boolean makePayment(Payment payment) {
payment.processPayment();
this.status = OrderStatus.COMPLETED;
return true;
}
public boolean addOrderLog(OrderLog orderLog) {
this.orderLog.add(orderLog);
return true;
}
}
// Example Main Class to demonstrate patterns in use
public class Main {
public static void main(String[] args) {
// Create an account using Factory Method
AccountFactory memberFactory = new MemberFactory();
Member member = (Member) memberFactory.createAccount("johnDoe", "password123", "John Doe", new Address());
// Create a product
Product product = new Product("P123", "Smartphone", "Latest model smartphone", 699.99, new ProductCategory(), member);
// Add items to the shopping cart using Command Pattern
ShoppingCart cart = new ShoppingCart();
Command addItemCommand = new AddItemToCartCommand(cart, new Item(product.getProductID(), 2, product.getAvailableCount()));
addItemCommand.execute();
// Place an order using Command Pattern
Order order = new Order("O12345");
Command placeOrderCommand = new PlaceOrderCommand(member, order);
placeOrderCommand.execute();
// Process payment using Strategy and Template Method Patterns
Payment payment = new CreditCardPayment();
PaymentStrategy paymentStrategy = new CreditCardPaymentStrategy();
paymentStrategy.pay(payment);
// Notify member about order update using Observer Pattern
SystemNotifier notifier = new SystemNotifier();
notifier.addObserver(member);
notifier.notifyObservers("Your order has been shipped.");
}
}