Strategy Design Pattern in Java: Selecting Algorithms Dynamically at Runtime

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

PatternPurpose
StrategySelect 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.

Leave a Reply

Your email address will not be published. Required fields are marked *