Design Patterns

The Strategy Pattern in Java

Software developers often face situations where an application needs to perform the same task in different ways depending on context. Hard-coding these variations with multiple if-else or switch statements can quickly make code difficult to maintain and extend.

This is where the Strategy Pattern becomes valuable.

What is the Strategy Pattern?

The Strategy Pattern is a behavioral design pattern that allows you to define a family of algorithms, encapsulate each one, and make them interchangeable at runtime.

Instead of embedding multiple algorithms directly into a class, you separate them into individual strategy classes and allow the application to choose which one to use.

Simple Definition

The Strategy Pattern enables selecting an algorithm or behavior at runtime without changing the code that uses it.

Why Use the Strategy Pattern?

Without the Strategy Pattern, code often looks like this:

public class PaymentService {

    public void processPayment(String paymentType, double amount) {
        if ("CREDIT_CARD".equals(paymentType)) {
            System.out.println("Processing credit card payment");
        } else if ("PAYPAL".equals(paymentType)) {
            System.out.println("Processing PayPal payment");
        } else if ("BANK_TRANSFER".equals(paymentType)) {
            System.out.println("Processing bank transfer payment");
        }
    }
}

Every time a new payment method is introduced, the class must be modified.

This violates the Open/Closed Principle, which states that software entities should be open for extension but closed for modification.

Structure of the Strategy Pattern

The Strategy Pattern consists of three main components:

1. Strategy Interface

Defines the common contract for all algorithms.

public interface PaymentStrategy {
    void pay(double amount);
}

2. Concrete Strategies

Implement specific algorithms.

Credit Card Strategy

public class CreditCardPayment implements PaymentStrategy {

    @Override
    public void pay(double amount) {
        System.out.println("Paid €" + amount + " using Credit Card");
    }
}

PayPal Strategy

public class PaypalPayment implements PaymentStrategy {

    @Override
    public void pay(double amount) {
        System.out.println("Paid €" + amount + " using PayPal");
    }
}

Bank Transfer Strategy

public class BankTransferPayment implements PaymentStrategy {

    @Override
    public void pay(double amount) {
        System.out.println("Paid €" + amount + " using Bank Transfer");
    }
}

3. Context

Uses a strategy without knowing its implementation details.

public class PaymentContext {

    private PaymentStrategy paymentStrategy;

    public PaymentContext(PaymentStrategy paymentStrategy) {
        this.paymentStrategy = paymentStrategy;
    }

    public void processPayment(double amount) {
        paymentStrategy.pay(amount);
    }
}

Using the Pattern

public class Main {

    public static void main(String[] args) {

        PaymentContext context =
                new PaymentContext(new CreditCardPayment());

        context.processPayment(100.0);

        context =
                new PaymentContext(new PaypalPayment());

        context.processPayment(50.0);
    }
}

Output:

Paid €100.0 using Credit Card
Paid €50.0 using PayPal

Notice that the PaymentContext never changes. Only the strategy changes.

Real-World Examples

The Strategy Pattern appears everywhere in modern software systems.

Payment Processing

  • Credit Card
  • PayPal
  • Apple Pay
  • Google Pay
  • Bank Transfer

Each payment method becomes a strategy.

Sorting Algorithms

An application may choose:

  • Quick Sort
  • Merge Sort
  • Bubble Sort

depending on data size and performance requirements.

Shipping Cost Calculation

Different shipping providers can implement:

  • Standard Shipping
  • Express Shipping
  • International Shipping

as separate strategies.

Authentication Providers

Applications may support:

  • Username/Password
  • Google Login
  • Microsoft Login
  • GitHub Login

Each authentication mechanism can be implemented as a strategy.

Strategy Pattern with Java Lambdas

Modern Java allows us to simplify the Strategy Pattern using functional interfaces.

Functional Interface

@FunctionalInterface
public interface DiscountStrategy {
    double applyDiscount(double price);
}

Using Lambdas

DiscountStrategy regular =
        price -> price;

DiscountStrategy silver =
        price -> price * 0.90;

DiscountStrategy gold =
        price -> price * 0.80;

System.out.println(gold.applyDiscount(100));

Output:

80.0

This approach reduces boilerplate while retaining the benefits of the pattern.

Advantages

Cleaner CodeEliminates large conditional blocks.
Easier MaintenanceEach algorithm lives in its own class.
Open for ExtensionAdding new strategies requires no changes to existing code.
Better TestabilityEach strategy can be tested independently.
Runtime FlexibilityBehavior can change dynamically during execution.

Disadvantages

More ClassesApplications may end up with many small strategy classes.
Additional ComplexityFor simple scenarios, the pattern may feel like overengineering.
Client AwarenessThe client often needs to know which strategy to choose.

Strategy Pattern vs State Pattern

These two patterns are often confused.

Strategy PatternState Pattern
Client chooses behaviorObject changes behavior based on internal state
Focuses on interchangeable algorithmsFocuses on state transitions
Strategy selection is externalState changes are internal

When Should You Use It?

Consider the Strategy Pattern when:

✅ You have multiple ways of performing the same task.

✅ You frequently add new business rules.

✅ You want to avoid large if-else or switch statements.

✅ You need to change behavior dynamically at runtime.

Avoid it when:

❌ There is only one algorithm.

❌ The behavior is unlikely to change.

❌ Simplicity is more important than flexibility.

Final Thoughts

The Strategy Pattern is one of the most practical design patterns in object-oriented programming. It promotes clean architecture, improves maintainability, and aligns well with SOLID principles—especially the Open/Closed Principle.

Whether you’re building payment systems, authentication frameworks, pricing engines, or cloud-native applications, the Strategy Pattern provides a flexible and scalable way to manage varying business behaviors.

The next time you find yourself writing a long chain of if-else statements, consider whether those branches are actually different strategies waiting to be extracted into their own classes.