Behavioral Pattern
Strategy Pattern
Define a family of algorithms, encapsulate each one, and make them interchangeable. Strategy lets the algorithm vary independently from clients that use it.
12 min readHigh Priority
1What is Strategy Pattern?
Real-World Analogy
Navigation App
Google Maps lets you choose between driving, walking, cycling, or public transit. Each is a different "strategy" to reach your destination. The app doesn't care which you pick - it just executes the chosen strategy.
Payment Options
An e-commerce site accepts credit card, PayPal, UPI, or crypto. Each payment method is a strategy. The checkout process remains the same, but the actual payment logic varies based on your choice.
Strategy is a behavioral pattern that lets you define a family of algorithms, put each into a separate class, and make their objects interchangeable. It enables selecting an algorithm at runtime.
Strategy Pattern Structure
Context delegates work to Strategy. Concrete strategies implement the algorithm.
2Problem It Solves
Without Strategy, you end up with massive conditional statements:
Without Strategy
public void pay(String type) {
if (type.equals("CREDIT")) {
// Credit card logic
} else if (type.equals("PAYPAL")) {
// PayPal logic
} else if (type.equals("UPI")) {
// UPI logic
} else if (type.equals("CRYPTO")) {
// Crypto logic
}
// Adding new method = modify this
}- - Violates Open/Closed
- - Hard to test
- - Tight coupling
With Strategy
public void pay(PaymentStrategy s) {
s.pay(amount);
// That's it!
}
// Each strategy is a separate class
// Adding new method = add new class
// No modification to existing code- + Open for extension
- + Easy to test
- + Loose coupling
3Implementation
Strategy Pattern - Payment Processing
// ========== Strategy Interface ==========
interface PaymentStrategy {
void pay(double amount);
boolean validate();
}
// ========== Concrete Strategies ==========
class CreditCardPayment implements PaymentStrategy {
private String cardNumber;
private String cvv;
public CreditCardPayment(String cardNumber, String cvv) {
this.cardNumber = cardNumber;
this.cvv = cvv;
}
@Override
public boolean validate() {
return cardNumber.length() == 16 && cvv.length() == 3;
}
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " using Credit Card");
}
}
class PayPalPayment implements PaymentStrategy {
private String email;
public PayPalPayment(String email) {
this.email = email;
}
@Override
public boolean validate() {
return email.contains("@");
}
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " using PayPal: " + email);
}
}
class UPIPayment implements PaymentStrategy {
private String upiId;
public UPIPayment(String upiId) {
this.upiId = upiId;
}
@Override
public boolean validate() {
return upiId.contains("@");
}
@Override
public void pay(double amount) {
System.out.println("Paid $" + amount + " using UPI: " + upiId);
}
}
// ========== Context ==========
class ShoppingCart {
private List<Item> items = new ArrayList<>();
private PaymentStrategy paymentStrategy;
public void addItem(Item item) {
items.add(item);
}
public double calculateTotal() {
return items.stream().mapToDouble(Item::getPrice).sum();
}
// Strategy can be set/changed at runtime
public void setPaymentStrategy(PaymentStrategy strategy) {
this.paymentStrategy = strategy;
}
public void checkout() {
double total = calculateTotal();
if (paymentStrategy.validate()) {
paymentStrategy.pay(total);
} else {
System.out.println("Payment validation failed");
}
}
}
// ========== Usage ==========
public class Main {
public static void main(String[] args) {
ShoppingCart cart = new ShoppingCart();
cart.addItem(new Item("Laptop", 999.99));
cart.addItem(new Item("Mouse", 29.99));
// Pay with Credit Card
cart.setPaymentStrategy(new CreditCardPayment("1234567890123456", "123"));
cart.checkout();
// Same cart, different payment method
cart.setPaymentStrategy(new PayPalPayment("user@email.com"));
cart.checkout();
// Or UPI
cart.setPaymentStrategy(new UPIPayment("user@okbank"));
cart.checkout();
}
}Output:
Paid $1029.98 using Credit Card Paid $1029.98 using PayPal: user@email.com Paid $1029.98 using UPI: user@okbank
4Real-World Applications
Sorting Algorithms
Collections.sort(list, comparator)
Java's Comparator is a strategy for comparing objects. You can swap between different comparison strategies.
Compression
ZIP, GZIP, LZ4, etc.
File archivers let you choose compression algorithms. Each is a strategy with different speed/ratio tradeoffs.
Validation Rules
Form validators
Different validation strategies: email, phone, password strength. Same form, different validators.
Caching Strategies
LRU, LFU, FIFO
Cache eviction policies are strategies. You can swap them without changing the cache implementation.
5Strategy vs State Pattern
These patterns look similar but solve different problems:
| Aspect | Strategy | State |
|---|---|---|
| Purpose | Choose algorithm | Manage state transitions |
| Who decides? | Client sets strategy | State changes itself |
| Awareness | Strategies don't know each other | States know about transitions |
| Example | Payment methods | Order status (pending → shipped → delivered) |
6Interview Follow-up Questions
Interview Follow-up Questions
Common follow-up questions interviewers ask
7Key Takeaways
1Strategy encapsulates algorithms in separate classes.
2Algorithms are interchangeable at runtime.
3Follows Open/Closed Principle - extend without modifying.
4Use when: multiple algorithms, runtime selection needed.
5Different from State: client chooses vs object decides.
6Examples: payment methods, sorting, compression, validation.