What Is the Strategy Pattern?

The Strategy pattern is a behavioral design pattern from the Gang of Four (GoF) catalog. It defines a family of algorithms, encapsulates each one in its own class, and makes them interchangeable. The client selects the appropriate algorithm at runtime without knowing its internal details.

In Java development, the Strategy pattern is one of the most practically useful patterns because it directly targets a common pain point: bloated conditional logic that's hard to test and extend.

The Problem It Solves

Imagine a payment processing class that handles multiple payment methods:

public void processPayment(String type, double amount) {
    if (type.equals("CREDIT")) { /* ... */ }
    else if (type.equals("PAYPAL")) { /* ... */ }
    else if (type.equals("CRYPTO")) { /* ... */ }
}

Every new payment method means modifying this method — violating the Open/Closed Principle. The class accumulates responsibilities, its WMC metric climbs, and testing each path becomes laborious.

Implementing the Strategy Pattern

Step 1: Define the Strategy Interface

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

Step 2: Implement Concrete Strategies

public class CreditCardStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Charging " + amount + " to credit card.");
    }
}

public class PayPalStrategy implements PaymentStrategy {
    @Override
    public void pay(double amount) {
        System.out.println("Sending " + amount + " via PayPal.");
    }
}

Step 3: Create the Context Class

public class PaymentProcessor {
    private PaymentStrategy strategy;

    public PaymentProcessor(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

    public void setStrategy(PaymentStrategy strategy) {
        this.strategy = strategy;
    }

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

Step 4: Use It in Client Code

PaymentProcessor processor = new PaymentProcessor(new CreditCardStrategy());
processor.processPayment(99.99);

processor.setStrategy(new PayPalStrategy());
processor.processPayment(49.50);

Impact on Code Metrics

Applying the Strategy pattern produces measurable metric improvements:

  • WMC decreases on the context class — complex conditional logic is removed.
  • LCOM improves — each strategy class is highly cohesive, focused on one algorithm.
  • CBO is spread more evenly rather than concentrated in one large class.

When to Use the Strategy Pattern

  • You have a class with multiple conditional branches selecting between algorithms.
  • You need to swap algorithms at runtime.
  • You want to isolate algorithm-specific logic for independent testing.
  • You anticipate adding new variants without modifying existing code.

When NOT to Use It

If you only ever have one algorithm and no foreseeable variants, the pattern adds unnecessary complexity. It also introduces more classes to your project — a small cost that's worth paying when the problem genuinely warrants it, but not for trivial cases.

Java 8+ Shortcut: Lambdas as Strategies

When the strategy interface has a single method (a functional interface), Java 8 lambdas can replace concrete strategy classes entirely:

PaymentProcessor processor = new PaymentProcessor(
    amount -> System.out.println("Paying " + amount + " with Bitcoin")
);

This keeps the pattern's benefits while dramatically reducing boilerplate, making Strategy one of the patterns that feels most at home in modern Java.