Design Online Shopping System like Amazon

Last Updated: December 19, 2025

Ashish

Ashish Pratap Singh

hard

In this chapter, we will explore the low-level design of online shopping system like Amazon in detail.

Let's start by clarifying the requirements:

1. Clarifying Requirements

Before starting the design, it's important to ask thoughtful questions to uncover hidden assumptions and better define the scope of the system.

Here is an example of how a conversation between the candidate and the interviewer might unfold:

After gathering the details, we can summarize the key system requirements.

1.1 Functional Requirements

  • Allow users to browse and search products by name and category
  • Enable users to view product details (title, description, price, availability)
  • Support adding and removing items in a shopping cart
  • Allow users to place orders from items in the cart
  • Validate inventory before confirming orders and update stock upon purchase
  • Allow users to view past orders
  • Support integration with multiple payment gateways (assume payment is always successful in this version)

1.2 Non-Functional Requirements

  • Modularity: The system should consist of well-separated components
  • Extensibility: The design should allow for future features like seller dashboards, product reviews, wishlists, and delivery tracking
  • Consistency: Inventory and order placement should be transactionally consistent to avoid overselling
  • Maintainability: The code should be organized, testable, and easy to extend

2. Identifying Core Entities

Core entities are the fundamental building blocks of our system. We identify them by analyzing key nouns (e.g., user, product, cart, order, inventory) and actions (e.g., browse, search, add to cart, checkout, authenticate) from the functional requirements. These typically translate directly into classes, enums, or interfaces in an object-oriented design.

Let’s walk through the functional requirements and extract the relevant entities:

1. Allow users to browse and search for products by name and category.

This points directly to a Product entity, which represents an item for sale. Products are classified, leading to a ProductCategory enum. The action of searching is encapsulated in a SearchService that operates on the product catalog.

2. Support adding and removing items in a shopping cart.

The concept of a ShoppingCart is a core entity that holds items a customer intends to buy. Each entry in the cart is a CartItem, which links a Product to a specific quantity. The cart itself is associated with a user's Account.

3. Allow customers to place orders and view their history.

The central entity for a purchase is the Order. It captures a transaction at a specific point in time and contains immutable OrderLineItem objects, which are snapshots of the products' details (name, price) at the time of purchase. An Order also has a lifecycle, which is managed by an OrderStatus enum (PLACED, SHIPPED, etc.).

4. A customer must be able to register and manage their details.

The user of the system is a Customer. This entity holds personal information, an Account for managing credentials and the cart, and an Address for shipping.

5. Validate inventory before confirming orders.

To manage product availability, an InventoryService is crucial. This service is responsible for checking and updating stock levels transactionally to prevent overselling.

6. Support integration with multiple payment gateways.

The need for flexible payment options suggests a PaymentStrategy interface, allowing different payment methods (e.g., CreditCardPaymentStrategyUPIPaymentStrategy) to be used interchangeably. A PaymentService coordinates the execution of the chosen strategy.

7. Provide a simplified, high-level interface to the system.

To manage the interactions between all these components, an OnlineShoppingSystem class acts as a Facade and Singleton. It provides a simple entry point for clients to perform actions like registering customers, adding products to the cart, and placing orders.

These core entities define the essential abstractions of an online shopping system like Amazon and will guide the structure of your low-level design and class diagrams.

3. Designing Classes and Relationships

This section breaks down the system's architecture into its fundamental classes, their responsibilities, and the relationships that connect them. We also explore the key design patterns that provide robustness and flexibility to the solution.

3.1 Class Definitions

The system is composed of several types of classes, each with a distinct role.

Enums

Enums
  • OrderStatus: Defines the discrete stages of an order's lifecycle, such as PLACED, SHIPPED, and DELIVERED.
  • ProductCategory: Classifies products into fixed categories like ELECTRONICS, BOOKS, and CLOTHING.

Data Classes

Address

A simple data class holding a customer's shipping location.

Address

Account

Encapsulates a user's credentials and owns their ShoppingCart.

Account

CartItem

A data class that links a Product to a specific quantity within a shopping cart.

CartItem

ShoppingCart

A container for a collection of CartItems, responsible for managing items and calculating the total price.

ShoppingCart

OrderLineItem

OrderLineItem

An immutable snapshot of a product's details (ID, name, price, quantity) at the moment an order is placed. This prevents issues if product prices or names change later.

Core Classes

Customer

Represents a user of the shopping system.

Customer

It acts as a concrete Observer, receiving status updates for its orders. It holds an Account and personal details.

Product (Abstract Class)

The base class for all items sold on the platform.

Product

Its construction is simplified by a nested Builder.

Order

The central class representing a customer's purchase.

Order

It acts as the Context for the State pattern (delegating actions to its currentState object) and as the Subject for the Observer pattern (notifying the Customer of status changes).

InventoryService, OrderService, PaymentService, SearchService

Service-layer classes that encapsulate specific business logic, such as managing stock, creating orders, processing payments, and searching the product catalog.

OnlineShoppingSystem (Singleton & Facade)

The primary entry point for the application.

OnlineShoppingSystem

It orchestrates all the services and manages the main data stores (products, customers, orders). It provides a simplified interface to the client, hiding the complex interactions between the various components.

3.2 Class Relationships

The relationships between classes define the system's structure and data flow.

Composition

  • A Customer "has-an" Account. The Account's lifecycle is managed by the Customer.
  • An Account "has-a" ShoppingCart.
  • A ShoppingCart "has-a" collection of CartItems.
  • An Order "has-a" list of OrderLineItems.
  • OnlineShoppingSystem "has-a" set of core services and manages the collections of all Products and Customers.

Association

  • An Order is associated with one Customer.
  • A CartItem is associated with a Product.
  • PaymentService is associated with a PaymentStrategy to process a payment.
  • An Order (Subject) is associated with its OrderObservers (the Customer).
  • An Order (Context) is associated with a single, current OrderState.

Inheritance

  • ProductDecorator extends Product. GiftWrapDecorator extends ProductDecorator.
  • Order extends the abstract Subject class.
  • Customer implements the OrderObserver interface.
  • Concrete OrderState classes implement the OrderState interface.
  • Concrete PaymentStrategy classes implement the PaymentStrategy interface.

Dependency

  • OnlineShoppingSystem (Facade) depends on its various service classes to execute commands.
  • OrderService depends on InventoryService to validate and update stock.
  • A client depends on Product.Builder to construct new Product objects.
  • An Order depends on OrderObserver to send notifications.

3.3 Key Design Patterns

Strategy Pattern

PaymentStrategy

The PaymentStrategy allows the algorithm for processing payments to be encapsulated and made interchangeable. The system can easily support new payment methods (e.g., PayPal, NetBanking) by creating new strategy classes without altering the PaymentService.

State Pattern

OrderState

The lifecycle of an Order is managed using the State pattern. The Order (Context) delegates its behavior to different OrderState objects (PlacedState, ShippedState). This cleanly separates state-specific logic and makes managing transitions robust and easy to understand.

Observer Pattern

OrderObserver

This pattern is fundamental for providing real-time updates. The Order (Subject) notifies the Customer (Observer) whenever its status changes. This decouples the core order processing logic from the notification mechanism.

Decorator Pattern

GiftWrapDecorator

The GiftWrapDecorator adds new functionality (extra cost and a modified description) to a Product object dynamically at runtime. This allows for flexible feature extension without creating a large number of subclasses.

Builder Pattern

The Product.Builder class is used for the step-by-step construction of a Product object. This is ideal for objects with many optional parameters (like description and category), providing a fluent API while ensuring the object is created in a valid state.

Facade Pattern

The OnlineShoppingSystem class acts as a facade. It provides a simple, high-level API (addProduct, placeOrder, addToCart) that hides the complex internal workflows involving multiple services, data models, and state management.

Singleton Pattern

OnlineShoppingSystem is implemented as a singleton to ensure a single, globally accessible point of control for the entire application. This centralizes the management of services and data stores.

3.4 Full Class Diagram

Online Shopping System Class Diagram

4. Implementation

4.1 Enums

Defines standard constants for order lifecycle and product classification to ensure consistent use across the system.

1class OrderStatus(Enum):
2    PENDING_PAYMENT = "PENDING_PAYMENT"
3    PLACED = "PLACED"
4    SHIPPED = "SHIPPED"
5    DELIVERED = "DELIVERED"
6    CANCELLED = "CANCELLED"
7    RETURNED = "RETURNED"
8
9
10class ProductCategory(Enum):
11    ELECTRONICS = "ELECTRONICS"
12    BOOKS = "BOOKS"
13    CLOTHING = "CLOTHING"
14    HOME_GOODS = "HOME_GOODS"
15    GROCERY = "GROCERY"

4.2 Address

Represents a customer’s delivery location.

1class Address:
2    def __init__(self, street: str, city: str, state: str, zip_code: str):
3        self.street = street
4        self.city = city
5        self.state = state
6        self.zip_code = zip_code
7
8    def __str__(self) -> str:
9        return f"{self.street}, {self.city}, {self.state} {self.zip_code}"

4.3 Customer (Observer)

1class Customer(OrderObserver):
2    def __init__(self, name: str, email: str, password: str, shipping_address: Address):
3        self.id = str(uuid.uuid4())
4        self.name = name
5        self.email = email
6        self.account = Account(email, password)
7        self.shipping_address = shipping_address
8
9    def update(self, order: 'Order') -> None:
10        print(f"[Notification for {self.name}]: Your order #{order.get_id()} status has been updated to: {order.get_status().value}.")
11
12    def get_id(self) -> str:
13        return self.id
14
15    def get_name(self) -> str:
16        return self.name
17
18    def get_account(self) -> 'Account':
19        return self.account
20
21    def get_shipping_address(self) -> Address:
22        return self.shipping_address
23
24    def set_shipping_address(self, address: Address) -> None:
25        self.shipping_address = address

Each Customer has a personal cart and is notified about order status changes using the Observer Pattern.

4.4 Product

1class Product(ABC):
2    def __init__(self):
3        self.id: str = ""
4        self.name: str = ""
5        self.description: str = ""
6        self.price: float = 0.0
7        self.category: ProductCategory = None
8
9    @abstractmethod
10    def get_id(self) -> str:
11        pass
12
13    @abstractmethod
14    def get_name(self) -> str:
15        pass
16
17    @abstractmethod
18    def get_description(self) -> str:
19        pass
20
21    @abstractmethod
22    def get_price(self) -> float:
23        pass
24
25    @abstractmethod
26    def get_category(self) -> ProductCategory:
27        pass
28
29    class BaseProduct:
30        def __init__(self, product_id: str, name: str, description: str, price: float, category: ProductCategory):
31            self.id = product_id
32            self.name = name
33            self.description = description
34            self.price = price
35            self.category = category
36
37        def get_id(self) -> str:
38            return self.id
39
40        def get_name(self) -> str:
41            return self.name
42
43        def get_description(self) -> str:
44            return self.description
45
46        def get_price(self) -> float:
47            return self.price
48
49        def get_category(self) -> ProductCategory:
50            return self.category
51
52    class Builder:
53        def __init__(self, name: str, price: float):
54            self.name = name
55            self.price = price
56            self.description = ""
57            self.category = None
58
59        def with_description(self, description: str) -> 'Product.Builder':
60            self.description = description
61            return self
62
63        def with_category(self, category: ProductCategory) -> 'Product.Builder':
64            self.category = category
65            return self
66
67        def build(self) -> 'Product':
68            return Product.BaseProduct(str(uuid.uuid4()), self.name, self.description, self.price, self.category)

Uses the Builder Pattern to simplify product creation.

Decorator

1class ProductDecorator(Product):
2    def __init__(self, decorated_product: Product):
3        super().__init__()
4        self.decorated_product = decorated_product
5
6    def get_id(self) -> str:
7        return self.decorated_product.get_id()
8
9    def get_name(self) -> str:
10        return self.decorated_product.get_name()
11
12    def get_price(self) -> float:
13        return self.decorated_product.get_price()
14
15    def get_description(self) -> str:
16        return self.decorated_product.get_description()
17
18    def get_category(self) -> ProductCategory:
19        return self.decorated_product.get_category()
20
21class GiftWrapDecorator(ProductDecorator):
22    GIFT_WRAP_COST = 5.00
23
24    def __init__(self, product: Product):
25        super().__init__(product)
26
27    def get_price(self) -> float:
28        return super().get_price() + self.GIFT_WRAP_COST
29
30    def get_description(self) -> str:
31        return super().get_description() + " (Gift Wrapped)"

CartItem

CartItem holds a product and quantity.

1class CartItem:
2    def __init__(self, product: Product, quantity: int):
3        self.product = product
4        self.quantity = quantity
5
6    def get_product(self) -> Product:
7        return self.product
8
9    def get_quantity(self) -> int:
10        return self.quantity
11
12    def increment_quantity(self, amount: int) -> None:
13        self.quantity += amount
14
15    def get_price(self) -> float:
16        return self.product.get_price() * self.quantity

ShoppingCart

ShoppingCart aggregates items and provides cart operations.

1class ShoppingCart:
2    def __init__(self):
3        self.items: Dict[str, CartItem] = {}
4
5    def add_item(self, product: Product, quantity: int) -> None:
6        if product.get_id() in self.items:
7            self.items[product.get_id()].increment_quantity(quantity)
8        else:
9            self.items[product.get_id()] = CartItem(product, quantity)
10
11    def remove_item(self, product_id: str) -> None:
12        if product_id in self.items:
13            del self.items[product_id]
14
15    def get_items(self) -> Dict[str, CartItem]:
16        return self.items.copy()
17
18    def calculate_total(self) -> float:
19        return sum(item.get_price() for item in self.items.values())
20
21    def clear_cart(self) -> None:
22        self.items.clear()

Account

Encapsulates a user’s credentials and their shopping cart.

1class Account:
2    def __init__(self, username: str, password: str):
3        self.username = username
4        self.password = password
5        self.cart = ShoppingCart()
6
7    def get_cart(self) -> ShoppingCart:
8        return self.cart

OrderLineItem

Represents immutable snapshots of a product at time of purchase.

1class OrderLineItem:
2    def __init__(self, product_id: str, product_name: str, quantity: int, price_at_purchase: float):
3        self.product_id = product_id
4        self.product_name = product_name
5        self.quantity = quantity
6        self.price_at_purchase = price_at_purchase
7
8    def get_product_id(self) -> str:
9        return self.product_id
10
11    def get_quantity(self) -> int:
12        return self.quantity

Order

1class Order(Subject):
2    def __init__(self, customer: Customer, items: List[OrderLineItem], shipping_address: Address, total_amount: float):
3        super().__init__()
4        self.id = str(uuid.uuid4())[:8]
5        self.customer = customer
6        self.items = items
7        self.shipping_address = shipping_address
8        self.total_amount = total_amount
9        self.order_date = datetime.now()
10        self.status = OrderStatus.PLACED
11        self.current_state = PlacedState()
12        self.add_observer(customer)
13
14    def ship_order(self) -> None:
15        self.current_state.ship(self)
16
17    def deliver_order(self) -> None:
18        self.current_state.deliver(self)
19
20    def cancel_order(self) -> None:
21        self.current_state.cancel(self)
22
23    def get_id(self) -> str:
24        return self.id
25
26    def get_status(self) -> OrderStatus:
27        return self.status
28
29    def set_state(self, state: OrderState) -> None:
30        self.current_state = state
31
32    def set_status(self, status: OrderStatus) -> None:
33        self.status = status
34        self.notify_observers(self)
35
36    def get_items(self) -> List[OrderLineItem]:
37        return self.items

Exceptions

1class OutOfStockException(Exception):
2    def __init__(self, message: str):
3        super().__init__(message)

Observer

1class OrderObserver(ABC):
2    @abstractmethod
3    def update(self, order: 'Order') -> None:
4        pass
5
6
7class Subject:
8    def __init__(self):
9        self.observers: List[OrderObserver] = []
10
11    def add_observer(self, observer: OrderObserver) -> None:
12        self.observers.append(observer)
13
14    def remove_observer(self, observer: OrderObserver) -> None:
15        if observer in self.observers:
16            self.observers.remove(observer)
17
18    def notify_observers(self, order: 'Order') -> None:
19        for observer in self.observers:
20            observer.update(order)

OrderState

Encapsulates state-specific behavior and transitions for orders using the State Pattern.

1class OrderState(ABC):
2    @abstractmethod
3    def ship(self, order: 'Order') -> None:
4        pass
5
6    @abstractmethod
7    def deliver(self, order: 'Order') -> None:
8        pass
9
10    @abstractmethod
11    def cancel(self, order: 'Order') -> None:
12        pass
13
14
15class PlacedState(OrderState):
16    def ship(self, order: 'Order') -> None:
17        print(f"Shipping order {order.get_id()}")
18        order.set_status(OrderStatus.SHIPPED)
19        order.set_state(ShippedState())
20
21    def deliver(self, order: 'Order') -> None:
22        print("Cannot deliver an order that has not been shipped.")
23
24    def cancel(self, order: 'Order') -> None:
25        print(f"Cancelling order {order.get_id()}")
26        order.set_status(OrderStatus.CANCELLED)
27        order.set_state(CancelledState())
28
29
30class ShippedState(OrderState):
31    def ship(self, order: 'Order') -> None:
32        print("Order is already shipped.")
33
34    def deliver(self, order: 'Order') -> None:
35        print(f"Delivering order {order.get_id()}")
36        order.set_status(OrderStatus.DELIVERED)
37        order.set_state(DeliveredState())
38
39    def cancel(self, order: 'Order') -> None:
40        print("Cannot cancel a shipped order.")
41
42
43class DeliveredState(OrderState):
44    def ship(self, order: 'Order') -> None:
45        print("Order already delivered.")
46
47    def deliver(self, order: 'Order') -> None:
48        print("Order already delivered.")
49
50    def cancel(self, order: 'Order') -> None:
51        print("Cannot cancel a delivered order.")
52
53
54class CancelledState(OrderState):
55    def ship(self, order: 'Order') -> None:
56        print("Cannot ship a cancelled order.")
57
58    def deliver(self, order: 'Order') -> None:
59        print("Cannot deliver a cancelled order.")
60
61    def cancel(self, order: 'Order') -> None:
62        print("Order is already cancelled.")

PaymentStrategy

Defines a flexible way to support multiple payment options using the Strategy Pattern.

1class PaymentStrategy(ABC):
2    @abstractmethod
3    def pay(self, amount: float) -> bool:
4        pass
5
6class UPIPaymentStrategy(PaymentStrategy):
7    def __init__(self, upi_id: str):
8        self.upi_id = upi_id
9
10    def pay(self, amount: float) -> bool:
11        print(f"Processing UPI payment of ${amount:.2f} with upi id {self.upi_id}.")
12        return True
13
14class CreditCardPaymentStrategy(PaymentStrategy):
15    def __init__(self, card_number: str):
16        self.card_number = card_number
17
18    def pay(self, amount: float) -> bool:
19        print(f"Processing credit card payment of ${amount:.2f} with card {self.card_number}.")
20        return True

InventoryService

Manages stock validation and deduction with thread safety.

1class InventoryService:
2    def __init__(self):
3        self.stock: Dict[str, int] = defaultdict(int)
4        self.lock = threading.Lock()
5
6    def add_stock(self, product: Product, quantity: int) -> None:
7        with self.lock:
8            self.stock[product.get_id()] += quantity
9
10    def update_stock_for_order(self, items: List[OrderLineItem]) -> None:
11        with self.lock:
12            # First, check if all items are in stock
13            for item in items:
14                if self.stock[item.get_product_id()] < item.get_quantity():
15                    raise OutOfStockException(f"Not enough stock for product ID: {item.get_product_id()}")
16            
17            # If all checks pass, deduct the stock
18            for item in items:
19                self.stock[item.get_product_id()] -= item.get_quantity()

OrderService

Coordinates inventory checks and order creation. Throws OutOfStockException if stock is insufficient.

1class OrderService:
2    def __init__(self, inventory_service: InventoryService):
3        self.inventory_service = inventory_service
4
5    def create_order(self, customer: Customer, cart: ShoppingCart) -> Order:
6        order_items = [
7            OrderLineItem(
8                cart_item.get_product().get_id(),
9                cart_item.get_product().get_name(),
10                cart_item.get_quantity(),
11                cart_item.get_product().get_price()
12            )
13            for cart_item in cart.get_items().values()
14        ]
15
16        self.inventory_service.update_stock_for_order(order_items)
17
18        return Order(customer, order_items, customer.get_shipping_address(), cart.calculate_total())

PaymentService

Delegates payment processing to the selected strategy implementation.

1class PaymentService:
2    def process_payment(self, strategy: PaymentStrategy, amount: float) -> bool:
3        return strategy.pay(amount)

SearchService

Provides name- and category-based product search functionality.

1class SearchService:
2    def __init__(self, product_catalog: Collection[Product]):
3        self.product_catalog = product_catalog
4
5    def search_by_name(self, name: str) -> List[Product]:
6        return [p for p in self.product_catalog if name.lower() in p.get_name().lower()]
7
8    def search_by_category(self, category: ProductCategory) -> List[Product]:
9        return [p for p in self.product_catalog if p.get_category() == category]

OnlineShoppingSystem

1class OnlineShoppingSystem:
2    _instance = None
3    _lock = threading.Lock()
4
5    def __new__(cls):
6        if cls._instance is None:
7            with cls._lock:
8                if cls._instance is None:
9                    cls._instance = super().__new__(cls)
10        return cls._instance
11
12    def __init__(self):
13        if hasattr(self, 'initialized'):
14            return
15        
16        self.products: Dict[str, Product] = {}
17        self.customers: Dict[str, Customer] = {}
18        self.orders: Dict[str, Order] = {}
19        
20        self.inventory_service = InventoryService()
21        self.payment_service = PaymentService()
22        self.order_service = OrderService(self.inventory_service)
23        self.search_service = SearchService(self.products.values())
24        
25        self.initialized = True
26
27    @classmethod
28    def get_instance(cls) -> 'OnlineShoppingSystem':
29        return cls()
30
31    def add_product(self, product: Product, initial_stock: int) -> None:
32        self.products[product.get_id()] = product
33        self.inventory_service.add_stock(product, initial_stock)
34
35    def register_customer(self, name: str, email: str, password: str, address: Address) -> Customer:
36        customer = Customer(name, email, password, address)
37        self.customers[customer.get_id()] = customer
38        return customer
39
40    def add_to_cart(self, customer_id: str, product_id: str, quantity: int) -> None:
41        customer = self.customers[customer_id]
42        product = self.products[product_id]
43        customer.get_account().get_cart().add_item(product, quantity)
44
45    def get_customer_cart(self, customer_id: str) -> ShoppingCart:
46        customer = self.customers[customer_id]
47        return customer.get_account().get_cart()
48
49    def search_products(self, name: str) -> List[Product]:
50        return self.search_service.search_by_name(name)
51
52    def place_order(self, customer_id: str, payment_strategy: PaymentStrategy) -> Optional[Order]:
53        customer = self.customers[customer_id]
54        cart = customer.get_account().get_cart()
55        
56        if not cart.get_items():
57            print("Cannot place an order with an empty cart.")
58            return None
59
60        # 1. Process payment
61        payment_success = self.payment_service.process_payment(payment_strategy, cart.calculate_total())
62        if not payment_success:
63            print("Payment failed. Please try again.")
64            return None
65
66        # 2. Create order and update inventory
67        try:
68            order = self.order_service.create_order(customer, cart)
69            self.orders[order.get_id()] = order
70
71            # 3. Clear the cart
72            cart.clear_cart()
73
74            return order
75        except Exception as e:
76            print(f"Order placement failed: {e}")
77            return None

OnlineShoppingDemo

1class OnlineShoppingDemo:
2    @staticmethod
3    def main():
4        # System Setup (Singleton and Services)
5        system = OnlineShoppingSystem.get_instance()
6
7        # Create and Add Products to Catalog (Builder Pattern)
8        laptop = Product.Builder("Dell XPS 15", 1499.99) \
9            .with_description("A powerful and sleek laptop.") \
10            .with_category(ProductCategory.ELECTRONICS) \
11            .build()
12        
13        book = Product.Builder("The Pragmatic Programmer", 45.50) \
14            .with_description("A classic book for software developers.") \
15            .with_category(ProductCategory.BOOKS) \
16            .build()
17
18        system.add_product(laptop, 10)  # 10 laptops in stock
19        system.add_product(book, 50)    # 50 books in stock
20
21        # Register a Customer
22        alice_address = Address("123 Main St", "Anytown", "CA", "12345")
23        alice = system.register_customer("Alice", "[email protected]", "password123", alice_address)
24
25        # Alice Shops
26        print("--- Alice starts shopping ---")
27
28        # Alice adds a laptop to her cart
29        system.add_to_cart(alice.get_id(), laptop.get_id(), 1)
30        print("Alice added a laptop to her cart.")
31
32        # Alice decides to gift-wrap the book (Decorator Pattern)
33        gift_wrapped_book = GiftWrapDecorator(book)
34        system.add_to_cart(alice.get_id(), gift_wrapped_book.get_id(), 1)
35        print(f"Alice added a gift-wrapped book. Original price: ${book.get_price():.2f}, New price: ${gift_wrapped_book.get_price():.2f}")
36
37        alice_cart = system.get_customer_cart(alice.get_id())
38        print(f"Alice's cart total: ${alice_cart.calculate_total():.2f}")
39
40        # Alice Checks Out
41        print("\n--- Alice proceeds to checkout ---")
42        alice_order = system.place_order(alice.get_id(), CreditCardPaymentStrategy("1234-5678-9876-5432"))
43        if alice_order is None:
44            print("Order placement failed.")
45            return
46
47        print(f"Order #{alice_order.get_id()} placed successfully for Alice.")
48
49        # Order State and Notifications (State, Observer Patterns)
50        print("\n--- Order processing starts ---")
51
52        # The warehouse ships the order
53        alice_order.ship_order()  # This will trigger a notification to Alice
54
55        # The delivery service marks the order as delivered
56        alice_order.deliver_order()  # This will also trigger a notification
57
58        # Try to cancel a delivered order (State pattern prevents this)
59        alice_order.cancel_order()
60
61        print("\n--- Out of Stock Scenario ---")
62        bob = system.register_customer("Bob", "[email protected]", "pass123", alice_address)
63
64        # Bob tries to buy 15 laptops, but only 9 are left (1 was bought by Alice)
65        system.add_to_cart(bob.get_id(), laptop.get_id(), 15)
66
67        bob_order = system.place_order(bob.get_id(), UPIPaymentStrategy("testupi@hdfc"))
68        if bob_order is None:
69            print("Bob's order was correctly prevented due to insufficient stock.")
70
71if __name__ == "__main__":
72    OnlineShoppingDemo.main()

5. Run and Test

Files29
decorators
entities
enums
exceptions
observers
services
states
strategies
online_shopping_demo.py
main
online_shopping_system.py
online_shopping_demo.pymain
Output

6. Quiz

Design Amazon - Quiz

1 / 21
Multiple Choice

Which entity is primarily responsible for managing the items a user intends to buy before placing an order in an online shopping system?

How helpful was this article?

Comments (1)


0/2000
Sort by
The Cap7 days ago

I didn't understand why did you complicated the Product class, till Builder class it makes sense where as BaseProduct is completley unnecessary and just making the design complex

Copilot extension content script