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)