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
ShoppingCartthat can accept various payment methods - Dynamic switching between strategies like
CreditCardandPayPal - 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
๐ UML Diagram
+-----------------------+
| PaymentStrategy | <<interface>>
+-----------------------+
| +pay(int) |
+-----------------------+
โฒ โฒ
+----------------------+ +----------------------+
| CreditCard | | Paypal |
+----------------------+ +----------------------+
| +pay(int) | | +pay(int) |
+----------------------+ +----------------------+
+---------------------+
| ShopingCart |
+---------------------+
| +addItem() |
| +pay(PaymentStrategy)|
+---------------------+
๐งพ Full Java Implementation with Balance Check
โ
1. PaymentStrategy.java
public interface PaymentStrategy {
void pay(int amount);
boolean hasSufficientBalance(int amount);
}
โ
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;
}
}
โ
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;
}
}
โ
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;
}
}
โ
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.");
}
}
}
โ
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
}
}
๐งช Sample Output
๐ณ Paid โน45000 using Credit Card [Holder: Alice]
โ PayPal payment failed: Insufficient balance.
โ 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
@Componentinjection 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)