0
0
LLDsystem_design~7 mins

Payment strategy pattern in LLD - System Design Guide

Choose your learning style9 modes available
Problem Statement
When a payment system supports multiple payment methods, hardcoding each method's logic in one place causes the code to become messy and difficult to maintain. Adding or changing payment methods requires modifying existing code, risking bugs and slowing development.
Solution
The payment strategy pattern solves this by defining a common interface for all payment methods and implementing each method as a separate class. The system selects the appropriate payment strategy at runtime, allowing easy addition or modification of payment methods without changing the core logic.
Architecture
PaymentClient
PaymentStrategy (I)
CreditCardPay
implements I

This diagram shows a PaymentClient using a PaymentStrategy interface to interact with different payment method implementations like CreditCardPay, PayPalPay, and BitcoinPay.

Trade-offs
✓ Pros
Enables adding new payment methods without changing existing code.
Improves code organization by separating payment logic into distinct classes.
Supports runtime selection of payment methods, increasing flexibility.
Facilitates testing each payment method independently.
✗ Cons
Increases the number of classes, which can complicate the codebase if overused.
Requires upfront design to define the common interface properly.
May introduce slight overhead in method calls due to abstraction.
Use when your system supports multiple payment methods and you expect to add or change them frequently, especially if you want to keep the codebase clean and maintainable.
Avoid when the system only supports one payment method or when payment logic is very simple and unlikely to change, as the pattern adds unnecessary complexity.
Real World Examples
Amazon
Amazon uses a strategy-like pattern to support multiple payment options such as credit cards, gift cards, and digital wallets, allowing seamless addition of new payment methods.
Uber
Uber applies the payment strategy pattern to switch between payment methods like credit cards, PayPal, and Uber credits dynamically during ride payments.
Shopify
Shopify uses this pattern to integrate various payment gateways, enabling merchants to choose and add payment options without changing core checkout logic.
Code Example
The before code uses if-else to handle payment methods, making it hard to add new methods. The after code defines a PaymentStrategy interface and separate classes for each payment method. PaymentProcessor uses a strategy instance to perform payment, enabling easy extension and cleaner code.
LLD
### Before: Without Strategy Pattern
class PaymentProcessor:
    def pay(self, method, amount):
        if method == 'credit_card':
            print(f"Processing credit card payment of ${amount}")
        elif method == 'paypal':
            print(f"Processing PayPal payment of ${amount}")
        else:
            print("Payment method not supported")

processor = PaymentProcessor()
processor.pay('credit_card', 100)


### After: With Strategy Pattern
from abc import ABC, abstractmethod

class PaymentStrategy(ABC):
    @abstractmethod
    def pay(self, amount):
        pass

class CreditCardPay(PaymentStrategy):
    def pay(self, amount):
        print(f"Processing credit card payment of ${amount}")

class PayPalPay(PaymentStrategy):
    def pay(self, amount):
        print(f"Processing PayPal payment of ${amount}")

class PaymentProcessor:
    def __init__(self, strategy: PaymentStrategy):
        self.strategy = strategy

    def pay(self, amount):
        self.strategy.pay(amount)

processor = PaymentProcessor(CreditCardPay())
processor.pay(100)

processor = PaymentProcessor(PayPalPay())
processor.pay(200)
OutputSuccess
Alternatives
Simple Conditional Logic
Uses if-else or switch statements to handle payment methods in one place instead of separate classes.
Use when: When the number of payment methods is very small and unlikely to grow.
Factory Pattern
Focuses on creating payment method objects, while strategy focuses on executing payment behavior.
Use when: When object creation logic is complex and needs central management.
Summary
The payment strategy pattern prevents messy code by separating payment methods into distinct classes.
It allows adding or changing payment methods without modifying existing code.
This pattern improves flexibility and maintainability in systems with multiple payment options.