Description / Meta Description
Learn the Strategy Design Pattern in Java with practical examples. Understand how Strategy eliminates complex if-else chains, enables dynamic behavior selection, improves extensibility, and powers real-world systems such as payment gateways, pricing engines, tax calculators, and Spring applications.
Strategy Design Pattern in Java: Selecting Algorithms Dynamically at Runtime
In the previous article, we introduced the Behavioral Design Pattern category and explored how behavioral patterns help objects communicate, collaborate, and distribute responsibilities.
Now we begin with arguably the most widely used Behavioral Pattern:
Strategy Pattern
If you’ve worked on:
- Payment Systems
- Pricing Engines
- Tax Calculators
- Notification Platforms
- Sorting Algorithms
- Spring Applications
you’ve likely encountered Strategy Pattern, whether you recognized it or not.
The Problem: Growing if-else Logic
Imagine you’re building a payment platform.
Initially, the application supports:
Credit Card
UPI
Wallet
A typical implementation starts like this:
public class PaymentService {
public void pay(
String paymentType) {
if(paymentType.equals("CARD")) {
System.out.println(
"Processing Card Payment");
}
else if(paymentType.equals("UPI")) {
System.out.println(
"Processing UPI Payment");
}
else if(paymentType.equals("WALLET")) {
System.out.println(
"Processing Wallet Payment");
}
}
}
Looks manageable.
Then business requirements evolve.
New payment methods arrive:
PayPal
Stripe
Apple Pay
Google Pay
Net Banking
Crypto
Now your code becomes:
if
else if
else if
else if
else if
else if
else if
Problems begin appearing:
- Difficult maintenance
- Repeated code changes
- Increased testing effort
- Violations of Open/Closed Principle
- Growing complexity
Every new payment type requires modifying existing production code.
This is exactly the problem Strategy Pattern solves.
What is Strategy Pattern?
Strategy is a Behavioral Design Pattern that:
Defines a family of algorithms, encapsulates each one separately, and makes them interchangeable at runtime.
In simpler terms:
Same Task
Different Ways
To Execute It
Examples:
Payment Processing
Card
UPI
Wallet
PayPal
Each is a strategy.
The application chooses the appropriate strategy at runtime.
Real Life Analogy
Suppose you need to travel from Delhi to Mumbai.
Options:
Flight
Train
Car
Bus
The destination remains:
Delhi → Mumbai
Only the travel strategy changes.
You don’t rewrite the journey.
You select a different strategy.
This is Strategy Pattern.
Strategy Architecture
Client
│
▼
Context
│
▼
Strategy Interface
▲
│
Card Strategy
UPI Strategy
Wallet Strategy
The context delegates work to the selected strategy.
Step 1: Create Strategy Interface
public interface PaymentStrategy {
void pay(double amount);
}
This defines a common contract.
Step 2: Create Concrete Strategies
Card Payment
public class CardPaymentStrategy
implements PaymentStrategy {
@Override
public void pay(
double amount) {
System.out.println(
"Card Payment: "
+ amount);
}
}
UPI Payment
public class UpiPaymentStrategy
implements PaymentStrategy {
@Override
public void pay(
double amount) {
System.out.println(
"UPI Payment: "
+ amount);
}
}
Wallet Payment
public class WalletPaymentStrategy
implements PaymentStrategy {
@Override
public void pay(
double amount) {
System.out.println(
"Wallet Payment: "
+ amount);
}
}
Step 3: Create Context
public class PaymentProcessor {
private PaymentStrategy strategy;
public PaymentProcessor(
PaymentStrategy strategy) {
this.strategy = strategy;
}
public void process(
double amount) {
strategy.pay(amount);
}
}
Notice:
Processor
Doesn't Know
Card
UPI
Wallet
It only knows:
PaymentStrategy
This is the key benefit.
Step 4: Client Usage
Card Payment:
PaymentStrategy strategy =
new CardPaymentStrategy();
PaymentProcessor processor =
new PaymentProcessor(
strategy);
processor.process(5000);
Output:
Card Payment: 5000
Switch to UPI:
PaymentStrategy strategy =
new UpiPaymentStrategy();
No code changes inside the processor.
Only the strategy changes.
Why Strategy Works
Without Strategy:
Payment Processor
if CARD
if UPI
if WALLET
if PAYPAL
if STRIPE
With Strategy:
Payment Processor
│
▼
Payment Strategy
│
┌────┼────┐
│ │ │
Card UPI Wallet
New payment methods become plug-ins.
Real Enterprise Example: Discount Calculation
E-commerce applications often support:
Festival Discount
Premium Customer Discount
Coupon Discount
Bulk Purchase Discount
Bad implementation:
if(customer.isPremium()) {
}
else if(couponApplied()) {
}
else if(festivalOffer()) {
}
Strategy implementation:
Discount Strategy
│
├── Premium Discount
├── Coupon Discount
├── Festival Discount
└── Bulk Discount
New discounts require new strategies.
Existing code remains untouched.
Tax Calculation Example
Different countries:
India GST
US Tax
Canada Tax
Europe VAT
Each calculation differs.
Strategy allows:
Tax Strategy
│
▼
Country Specific Logic
without changing invoice processing code.
Java Collections Example
Most developers unknowingly use Strategy.
Sorting:
Collections.sort(
employees,
comparator);
The comparator is a Strategy.
Example:
Comparator<Employee>
can sort by:
Name
Salary
Age
Experience
Different algorithms.
Same operation.
Spring Framework Example
Spring Dependency Injection often enables Strategy naturally.
Interface:
public interface NotificationService {
void send();
}
Implementations:
Email Notification
SMS Notification
Push Notification
Spring injects the desired strategy.
Client remains unchanged.
Benefits of Strategy Pattern
1. Eliminates if-else Chains
One of the biggest advantages.
2. Open/Closed Principle
Add new strategies.
Avoid modifying existing code.
3. Better Testability
Each strategy can be tested independently.
4. Runtime Flexibility
Algorithms can change dynamically.
5. Improved Maintainability
Business logic becomes isolated.
Common Mistakes
Mistake 1: Too Few Strategies
If only one implementation exists:
One Interface
One Class
Strategy may be unnecessary.
Mistake 2: Context Becoming Too Smart
Context should delegate.
Avoid embedding strategy logic inside context.
Bad:
if(strategy instanceof CardStrategy)
This defeats the pattern.
Mistake 3: Strategy Explosion
Creating dozens of tiny strategies unnecessarily can complicate design.
Use Strategy where behavior genuinely varies.
Strategy vs State Pattern
Common interview question.
Strategy
Purpose:
Choose Behavior
Example:
Card Payment
UPI Payment
Wallet Payment
Client selects strategy.
State
Purpose:
Behavior Changes
Automatically Based On State
Example:
Order Created
Order Paid
Order Delivered
Object changes behavior based on internal state.
Strategy vs Command
Strategy
Represents:
Algorithm
Command
Represents:
Request
Action
Operation
Different intentions.
When Should You Use Strategy?
Use Strategy when:
✔ Multiple algorithms exist
✔ Behavior changes frequently
✔ Runtime selection is required
✔ Large if-else chains exist
✔ Open/Closed Principle matters
Examples:
- Payments
- Pricing
- Tax Calculations
- Sorting
- Notifications
- Authentication
Avoid Strategy when:
❌ Only one algorithm exists
❌ Behavior rarely changes
❌ Simpler code is sufficient
Behavioral Patterns Covered So Far
| Pattern | Purpose |
|---|---|
| Strategy | Select algorithms dynamically |
Behavioral Pattern Cheat Sheet
Strategy
→ Choose Behavior Dynamically
Think:
Same Task
Different Ways
To Execute It
That is the essence of Strategy Pattern.
Final Thoughts
The Strategy Pattern solves one of the most common software design problems:
How do we support multiple behaviors without filling the codebase with complex conditionals?
By encapsulating algorithms into interchangeable strategies, we gain:
- Flexibility
- Extensibility
- Maintainability
- Testability
This is why Strategy appears everywhere in enterprise systems:
- Payment Platforms
- Pricing Engines
- Tax Calculators
- Notification Systems
- Spring Applications
- Java Collections
Whenever you encounter growing if-else chains based on behavior selection, Strategy Pattern should be one of the first solutions you consider.
In the next article, we’ll explore another extremely popular Behavioral Pattern:
Observer Design Pattern — Building Event-Driven Systems Through Publish-Subscribe Communication
You’ll learn how Kafka consumers, Spring Events, notification systems, stock market feeds, and reactive architectures rely heavily on Observer Pattern concepts.