DEV Community

DevCorner2
DevCorner2

Posted on

πŸ’³ Implementing Strategy Design Pattern in a Shopping Cart System [Java LLD + Balance Check]

In this blog, we’ll explore how to use the Strategy Design Pattern to build a clean, extensible payment system for an online shopping cart. We'll also simulate balance checking to reject payments if funds are insufficient.


πŸš€ What We'll Build

  • A ShoppingCart that can accept various payment methods
  • Dynamic switching between strategies like CreditCard and PayPal
  • Balance validation for each payment type
  • Loose coupling between business logic and payment algorithms

🧠 Why Strategy Pattern?

The Strategy Pattern enables:

  • Defining multiple payment algorithms independently
  • Selecting an algorithm at runtime
  • Extending behavior without modifying core logic (Open/Closed Principle)

πŸ”§ Core Components

Component Responsibility
PaymentStrategy Interface for all payment types
CreditCard, Paypal Implements actual payment behavior
Item Represents a purchasable item
ShopingCart Holds items and delegates payment logic
Test Acts as the client to test different strategies

πŸ“¦ Project Structure

πŸ“ Strategy/
β”œβ”€β”€ CreditCard.java
β”œβ”€β”€ Paypal.java
β”œβ”€β”€ Item.java
β”œβ”€β”€ PaymentStrategy.java
β”œβ”€β”€ ShopingCart.java
└── Test.java
Enter fullscreen mode Exit fullscreen mode

πŸ“ UML Diagram

               +-----------------------+
               |   PaymentStrategy     |  <<interface>>
               +-----------------------+
               | +pay(int)             |
               +-----------------------+
                  β–²               β–²
   +----------------------+   +----------------------+
   |    CreditCard        |   |       Paypal         |
   +----------------------+   +----------------------+
   | +pay(int)            |   | +pay(int)            |
   +----------------------+   +----------------------+

               +---------------------+
               |    ShopingCart      |
               +---------------------+
               | +addItem()          |
               | +pay(PaymentStrategy)|
               +---------------------+
Enter fullscreen mode Exit fullscreen mode

🧾 Full Java Implementation with Balance Check

βœ… 1. PaymentStrategy.java

public interface PaymentStrategy {
    void pay(int amount);
    boolean hasSufficientBalance(int amount);
}
Enter fullscreen mode Exit fullscreen mode

βœ… 2. CreditCard.java

public class CreditCard implements PaymentStrategy {
    private final String name;
    private final String cardNumber;
    private final String cvv;
    private int balance;

    public CreditCard(String name, String cardNumber, String cvv, int balance) {
        this.name = name;
        this.cardNumber = cardNumber;
        this.cvv = cvv;
        this.balance = balance;
    }

    @Override
    public void pay(int amount) {
        if (hasSufficientBalance(amount)) {
            balance -= amount;
            System.out.println("πŸ’³ Paid β‚Ή" + amount + " using Credit Card [Holder: " + name + "]");
        } else {
            System.out.println("❌ Credit Card payment failed: Insufficient balance.");
        }
    }

    @Override
    public boolean hasSufficientBalance(int amount) {
        return balance >= amount;
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 3. Paypal.java

public class Paypal implements PaymentStrategy {
    private final String email;
    private final String password;
    private int balance;

    public Paypal(String email, String password, int balance) {
        this.email = email;
        this.password = password;
        this.balance = balance;
    }

    @Override
    public void pay(int amount) {
        if (hasSufficientBalance(amount)) {
            balance -= amount;
            System.out.println("🌐 Paid β‚Ή" + amount + " using PayPal [Email: " + email + "]");
        } else {
            System.out.println("❌ PayPal payment failed: Insufficient balance.");
        }
    }

    @Override
    public boolean hasSufficientBalance(int amount) {
        return balance >= amount;
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 4. Item.java

public class Item {
    private final String name;
    private final int price;

    public Item(String name, int price) {
        this.name = name;
        this.price = price;
    }

    public int getPrice() {
        return price;
    }

    public String getName() {
        return name;
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 5. ShopingCart.java

import java.util.ArrayList;
import java.util.List;

public class ShopingCart {
    private final List<Item> items = new ArrayList<>();

    public void addItem(Item item) {
        items.add(item);
    }

    public int calculateTotal() {
        return items.stream().mapToInt(Item::getPrice).sum();
    }

    public void pay(PaymentStrategy strategy) {
        int amount = calculateTotal();
        if (strategy.hasSufficientBalance(amount)) {
            strategy.pay(amount);
        } else {
            System.out.println("❗ Transaction declined due to insufficient balance.");
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

βœ… 6. Test.java

public class Test {
    public static void main(String[] args) {
        ShopingCart cart = new ShopingCart();
        cart.addItem(new Item("Laptop", 40000));
        cart.addItem(new Item("Keyboard", 5000));

        PaymentStrategy creditCard = new CreditCard("Alice", "1234-5678-9012", "999", 45000);
        PaymentStrategy paypal = new Paypal("bob@example.com", "bob@123", 30000);

        // Try Credit Card
        cart.pay(creditCard); // Success

        // Try PayPal
        cart.pay(paypal);     // Fail due to insufficient balance
    }
}
Enter fullscreen mode Exit fullscreen mode

πŸ§ͺ Sample Output

πŸ’³ Paid β‚Ή45000 using Credit Card [Holder: Alice]
❌ PayPal payment failed: Insufficient balance.
Enter fullscreen mode Exit fullscreen mode

βœ… Benefits of Strategy Pattern

Advantage Explanation
βœ… Decouples behavior Payment logic is separate from business logic
βœ… Runtime flexibility Switch strategies without code change
βœ… Easy to extend Add new payment types without breaking anything
βœ… Testable Each strategy can be independently tested

⚠️ Gotchas

  • You may need a Strategy Factory if many implementations exist.
  • Always validate strategy readiness (e.g., balance) before execution.
  • Consider using Spring's @Component injection for runtime wiring.

🧠 Interview Tip

If asked to design a payment system, checkout flow, or modular transaction handler, the Strategy Pattern is a great fit.
Mention how this approach avoids if-else chains and follows OCP (Open/Closed Principle).


Top comments (0)