Logo

Real-World Case Study: E-Commerce Order Processing System

4 min read
Lesson slides
1 / 15

Real-World Case Study: E-Commerce Order Processing

Combining Multiple Design Patterns in One System

Problem Statement

You're designing an e-commerce system that needs to:

  1. Handle different types of products (physical, digital, subscription)
  2. Support multiple payment methods
  3. Send notifications to various channels
  4. Process orders with complex business rules
  5. Support order modifications and cancellations

System Architecture Overview

graph TB
    subgraph "Client Layer"
        UI[Web UI]
        API[REST API]
    end
    
    subgraph "Facade Layer"
        OMF[OrderManagementFacade]
    end
    
    subgraph "Business Logic"
        OB[OrderBuilder]
        PF[ProductFactory]
        PS[PaymentStrategy]
        OP[OrderProcessor]
    end
    
    subgraph "Services"
        IS[InventoryService]
        PS2[PaymentService]
        SS[ShippingService]
        NS[NotificationService]
    end
    
    subgraph "Command System"
        CI[CommandInvoker]
        POC[PlaceOrderCommand]
        COC[CancelOrderCommand]
    end
    
    UI --> OMF
    API --> OMF
    OMF --> OB
    OMF --> PF
    OMF --> PS
    OMF --> OP
    OMF --> IS
    OMF --> PS2
    OMF --> SS
    OMF --> NS
    OMF --> CI
    CI --> POC
    CI --> COC

Pattern Integration Flow

sequenceDiagram
    participant Client
    participant Facade as OrderManagementFacade
    participant Builder as OrderBuilder
    participant Factory as ProductFactory
    participant Strategy as PaymentStrategy
    participant Observer as NotificationSystem
    participant Command as CommandInvoker
    
    Client->>Facade: placeOrder(orderData)
    Facade->>Builder: createOrder()
    Builder->>Factory: createProduct(type, data)
    Factory-->>Builder: Product
    Builder-->>Facade: Order
    Facade->>Strategy: processPayment(order)
    Strategy-->>Facade: PaymentResult
    Facade->>Observer: notifyStatusChange("paid")
    Observer-->>Facade: notifications sent
    Facade->>Command: execute(PlaceOrderCommand)
    Command-->>Facade: order placed
    Facade-->>Client: OrderConfirmation

Analysis and Pattern Selection

Creational Patterns Needed:

  1. Factory Pattern for Product Creation:
class ProductFactory: 
    @staticmethod
    def create_product(product_type, **kwargs):
        if product_type == "physical":
            return PhysicalProduct(**kwargs)
        elif product_type == "digital":
            return DigitalProduct(**kwargs)
        elif product_type == "subscription":
            return SubscriptionProduct(**kwargs)
  1. Builder Pattern for Order Creation:
class OrderBuilder:
    def __init__(self):
        self.order = Order()
    
    def add_product(self, product):
        self.order.products.append(product)
        return self
    
    def set_customer(self, customer):
        self.order.customer = customer
        return self
    
    def set_shipping_address(self, address):
        self.order.shipping_address = address
        return self
    
    def apply_discount(self, discount):
        self.order.discount = discount
        return self

Structural Patterns Needed:

  1. Decorator Pattern for Order Processing:
class OrderProcessorDecorator:
    def __init__(self, processor):
        self.processor = processor
    
    def process(self, order):
        return self.processor.process(order)
 
class TaxCalculatorDecorator(OrderProcessorDecorator):
    def process(self, order):
        result = self.processor.process(order)
        # Add tax calculation logic
        return result
 
class ShippingCalculatorDecorator(OrderProcessorDecorator):
    def process(self, order):
        result = self.processor.process(order)
        # Add shipping calculation logic
        return result
  1. Facade Pattern for Order Management:
class OrderManagementFacade:
    def __init__(self):
        self.inventory = InventoryService()
        self.payment = PaymentService()
        self.shipping = ShippingService()
        self.notification = NotificationService()
    
    def place_order(self, order):
        # Orchestrate all services
        self.inventory.reserve_items(order.products)
        payment_result = self.payment.process_payment(order)
        if payment_result.success:
            self.shipping.schedule_delivery(order)
            self.notification.send_confirmation(order)
        return payment_result

Behavioral Patterns Needed:

  1. Strategy Pattern for Payment Processing:
class PaymentProcessor:
    def __init__(self):
        self.strategy = None
    
    def set_payment_strategy(self, strategy):
        self.strategy = strategy
    
    def process_payment(self, order):
        return self.strategy.pay(order.total_amount)
  1. Observer Pattern for Order Status Updates:
class Order(Subject):
    def __init__(self):
        super().__init__()
        self._status = "pending"
    
    @property
    def status(self):
        return self._status
    
    @status.setter
    def status(self, new_status):
        self._status = new_status
        self.notify(f"Order status changed to {new_status}")
  1. Command Pattern for Order Operations:
class PlaceOrderCommand(Command):
    def __init__(self, order_service, order):
        self.order_service = order_service
        self.order = order
    
    def execute(self):
        return self.order_service.place_order(self.order)
    
    def undo(self):
        return self.order_service.cancel_order(self.order)

Pattern Selection Decision Matrix

graph TD
    A[Design Decision] --> B{Object Creation Complexity?}
    B -->|Simple| C[Direct Constructor]
    B -->|Multiple Types| D[Factory Pattern]
    B -->|Many Parameters| E[Builder Pattern]
    B -->|Single Instance| F[Singleton Pattern]
    
    A --> G{Interface Compatibility?}
    G -->|Incompatible| H[Adapter Pattern]
    G -->|Add Behavior| I[Decorator Pattern]
    G -->|Simplify Complex| J[Facade Pattern]
    
    A --> K{Communication Pattern?}
    K -->|One-to-Many Updates| L[Observer Pattern]
    K -->|Multiple Algorithms| M[Strategy Pattern]
    K -->|Queue/Undo Operations| N[Command Pattern]

Complete Integration Example:

# Using multiple patterns together
def process_ecommerce_order():
    # Builder pattern for order creation
    order = (OrderBuilder()
             .set_customer(customer)
             .add_product(ProductFactory.create_product("physical", name="Laptop"))
             .add_product(ProductFactory.create_product("digital", name="Software"))
             .set_shipping_address(address)
             .build())
    
    # Strategy pattern for payment
    payment_processor = PaymentProcessor()
    payment_processor.set_payment_strategy(CreditCardPayment("1234567890"))
    
    # Observer pattern for notifications
    order.attach(EmailNotification())
    order.attach(SMSNotification())
    
    # Decorator pattern for processing
    processor = BasicOrderProcessor()
    processor = TaxCalculatorDecorator(processor)
    processor = ShippingCalculatorDecorator(processor)
    
    # Command pattern for execution
    command = PlaceOrderCommand(order_service, order)
    result = command.execute()
    
    # Facade pattern for coordination
    facade = OrderManagementFacade()
    return facade.place_order(order)

Pattern Selection Reasoning Matrix:

PatternProblem SolvedWhy ChosenAlternative Considered
FactoryDifferent product typesRuntime type determinationDirect instantiation (too rigid)
BuilderComplex order creationMany optional parametersConstructor overloading (unwieldy)
StrategyPayment methodsRuntime algorithm switchingIf-else chains (hard to extend)
ObserverNotificationsDecoupled communicationDirect method calls (tight coupling)
DecoratorOrder processingFlexible responsibility chainInheritance (explosion of classes)
CommandOrder operationsUndo/redo + queuingDirect method calls (no undo)
FacadeSystem complexitySimplified interfaceDirect service calls (complex client)