The Strategy pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable at runtime.

Problem

You have multiple ways to perform an operation and want to switch between them without modifying client code.

Solution

  interface PaymentStrategy {
    void pay(double amount);
}

class CreditCardPayment implements PaymentStrategy {
    private final String cardNumber;
    CreditCardPayment(String cardNumber) { this.cardNumber = cardNumber; }
    public void pay(double amount) {
        System.out.println("Paid $" + amount + " with card " + cardNumber);
    }
}

class PayPalPayment implements PaymentStrategy {
    private final String email;
    PayPalPayment(String email) { this.email = email; }
    public void pay(double amount) {
        System.out.println("Paid $" + amount + " via PayPal (" + email + ")");
    }
}

class ShoppingCart {
    private PaymentStrategy paymentStrategy;

    void setPaymentStrategy(PaymentStrategy strategy) {
        this.paymentStrategy = strategy;
    }

    void checkout(double total) {
        paymentStrategy.pay(total);
    }
}

// Usage
ShoppingCart cart = new ShoppingCart();
cart.setPaymentStrategy(new CreditCardPayment("4111-1111-1111-1111"));
cart.checkout(99.99);
  

Strategy with Lambda

Since Java 8, simple strategies are often lambdas:

  interface DiscountStrategy {
    double apply(double price);
}

DiscountStrategy tenPercent = price -> price * 0.9;
DiscountStrategy fixed = price -> price - 10;
DiscountStrategy noDiscount = price -> price;

double finalPrice = tenPercent.apply(100.0); // 90.0
  

Java Examples

  // Comparator is a strategy for sorting
list.sort(Comparator.comparing(Person::getName));
list.sort(Comparator.comparingInt(Person::getAge));

// ThreadPoolExecutor rejection policies
new ThreadPoolExecutor.CallerRunsPolicy();
new ThreadPoolExecutor.AbortPolicy();

// Spring Resource loading strategies
ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
  

Strategy vs State vs Template Method

Pattern Varies Selection
Strategy Algorithm Client chooses
State Behavior by state Object changes internally
Template Method Steps in algorithm Inheritance, fixed skeleton

When to Use

  • Multiple algorithms for the same task
  • Avoid conditional statements (if/else or switch) for algorithm selection
  • Hide complex algorithm-specific data from clients

Best Practices

  • Inject strategy via constructor or setter — enable testing with mock strategies
  • Use enums with strategy behavior for fixed, known algorithms
  • Prefer lambdas for simple, stateless strategies
  • Combine with Factory Method to create strategies based on configuration