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
andPayPal
- 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
@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)