Skip to content
intermediatePhase 49 · Low-Level Design

Strategy Pattern

Define a family of algorithms and make them interchangeable.

30m
0 problems
Topic Progress0%

Strategy Interface

The Strategy pattern defines a family of algorithms and makes them interchangeable.

Core Structure

┌──────────────────────────┐
│       Context             │
├──────────────────────────┤
│ - strategy: Strategy     │
├──────────────────────────┤
│ + setStrategy(Strategy)  │
│ + executeStrategy()      │
└──────────┬───────────────┘
           │ uses
           ▼
┌──────────────────────────┐
│    «interface»           │
│      Strategy            │
├──────────────────────────┤
│ + execute(data): Result  │
└──────────┬───────────────┘
           │ implemented by
     ┌─────┴──────┐
     │            │
┌────┴─────┐ ┌───┴──────┐
│ConcreteA │ │ConcreteB │
└──────────┘ └──────────┘

Strategy Interface

// Strategy interface defines the algorithm contract
public interface SortStrategy {
    void sort(int[] array);
    String getName();
}

// Concrete strategies implement different algorithms
public class BubbleSort implements SortStrategy {
    @Override
    public void sort(int[] array) {
        // Bubble sort implementation
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array.length - i - 1; j++) {
                if (array[j] > array[j + 1]) {
                    swap(array, j, j + 1);
                }
            }
        }
    }
    
    @Override
    public String getName() { return "Bubble Sort"; }
}

public class QuickSort implements SortStrategy {
    @Override
    public void sort(int[] array) {
        // QuickSort implementation
        quickSort(array, 0, array.length - 1);
    }
    
    @Override
    public String getName() { return "Quick Sort"; }
}

When to Define Strategy Interface

  • Multiple algorithms for the same problem
  • Algorithm selection at runtime
  • Eliminating conditional statements
  • Making algorithms interchangeable

Strategy Interface Guidelines

  1. Small interface: 1-3 methods ideally
  2. Clear contract: What the strategy does
  3. No side effects: Strategy shouldn't modify context
  4. Stateless when possible: Strategies without state are easier to reuse

Concrete Strategies

Concrete strategies implement the strategy interface with specific algorithms.

Payment Processing Example

public interface PaymentStrategy {
    PaymentResult pay(Money amount, PaymentDetails details);
    boolean supportsRefund();
}

public class CreditCardStrategy implements PaymentStrategy {
    private final String cardNumber;
    private final String cvv;
    
    public CreditCardStrategy(String cardNumber, String cvv) {
        this.cardNumber = cardNumber;
        this.cvv = cvv;
    }
    
    @Override
    public PaymentResult pay(Money amount, PaymentDetails details) {
        // Credit card processing logic
        return new PaymentResult(true, "CC-" + UUID.randomUUID());
    }
    
    @Override
    public boolean supportsRefund() { return true; }
}

public class PayPalStrategy implements PaymentStrategy {
    private final String email;
    
    public PayPalStrategy(String email) {
        this.email = email;
    }
    
    @Override
    public PaymentResult pay(Money amount, PaymentDetails details) {
        // PayPal processing logic
        return new PaymentResult(true, "PP-" + UUID.randomUUID());
    }
    
    @Override
    public boolean supportsRefund() { return true; }
}

public class CryptoStrategy implements PaymentStrategy {
    @Override
    public PaymentResult pay(Money amount, PaymentDetails details) {
        // Cryptocurrency processing logic
        return new PaymentResult(true, "BTC-" + UUID.randomUUID());
    }
    
    @Override
    public boolean supportsRefund() { return false; }
}

Pricing Strategies

public interface PricingStrategy {
    Money calculatePrice(Order order);
}

public class RegularPricing implements PricingStrategy {
    public Money calculatePrice(Order order) {
        return order.getSubtotal();
    }
}

public class PremiumPricing implements PricingStrategy {
    private final double discountRate;
    
    public PremiumPricing(double discountRate) {
        this.discountRate = discountRate;
    }
    
    public Money calculatePrice(Order order) {
        return order.getSubtotal().multiply(1 - discountRate);
    }
}

public class BulkPricing implements PricingStrategy {
    public Money calculatePrice(Order order) {
        if (order.getItemCount() >= 10) {
            return order.getSubtotal().multiply(0.8); // 20% off
        }
        return order.getSubtotal();
    }
}

Strategy Selection

Strategy Use When
RegularPricing Default pricing
PremiumPricing Subscription users
BulkPricing Large orders
PromoPricing Active promotion

Context Class

The Context class uses the strategy and allows swapping strategies at runtime.

Context Implementation

public class PriceCalculator {
    private PricingStrategy strategy;
    
    // Constructor injection
    public PriceCalculator(PricingStrategy strategy) {
        this.strategy = strategy;
    }
    
    // Setter injection for runtime swapping
    public void setStrategy(PricingStrategy strategy) {
        this.strategy = strategy;
    }
    
    public Money calculate(Order order) {
        return strategy.calculatePrice(order);
    }
}

Context with Strategy Selection

public class PaymentService {
    private final Map<PaymentType, PaymentStrategy> strategies;
    
    public PaymentService() {
        strategies = new HashMap<>();
        strategies.put(PaymentType.CREDIT_CARD, new CreditCardStrategy());
        strategies.put(PaymentType.PAYPAL, new PayPalStrategy());
        strategies.put(PaymentType.CRYPTO, new CryptoStrategy());
    }
    
    public PaymentResult processPayment(Order order, PaymentType type) {
        PaymentStrategy strategy = strategies.get(type);
        if (strategy == null) {
            throw new UnsupportedPaymentType(type);
        }
        return strategy.pay(order.getTotal(), order.getPaymentDetails());
    }
}

Runtime Strategy Swapping

// Start with regular pricing
PriceCalculator calculator = new PriceCalculator(new RegularPricing());
Money price = calculator.calculate(order); // Regular price

// User becomes premium member
calculator.setStrategy(new PremiumPricing(0.1));
price = calculator.calculate(order); // 10% discount

// During bulk promotion
calculator.setStrategy(new BulkPricing());
price = calculator.calculate(order); // Bulk discount if applicable

Strategy with Dependency Injection

// Spring-style injection
@Service
public class OrderService {
    private final PricingStrategy pricingStrategy;
    
    @Autowired
    public OrderService(PricingStrategy pricingStrategy) {
        this.pricingStrategy = pricingStrategy;
    }
    
    public Order calculateOrder(Order order) {
        Money total = pricingStrategy.calculatePrice(order);
        order.setTotal(total);
        return order;
    }
}

// Different beans for different strategies
@Configuration
public class PricingConfig {
    @Bean
    @Profile("default")
    public PricingStrategy regularPricing() {
        return new RegularPricing();
    }
    
    @Bean
    @Profile("premium")
    public PricingStrategy premiumPricing() {
        return new PremiumPricing(0.15);
    }
}

Benefits of Strategy Pattern

  1. Open-Closed Principle: Add new strategies without modifying context
  2. Eliminates conditionals: No if/else chains for algorithm selection
  3. Runtime flexibility: Swap algorithms during execution
  4. Testability: Test each strategy in isolation
  5. Reusability: Strategies can be shared across contexts

Practice Problems

0/3solved
Design Strategy Pattern System

Design a scalable Strategy Pattern system. Cover high-level architecture, data model, and API design.

Solution
// Complete system design:
// - Functional + Non-functional requirements
// - Capacity estimation
// - Data model (SQL/NoSQL choice)
// - API endpoints
// - Component architecture
// - Scaling strategy
// - Monitoring & reliability
Strategy Pattern Scaling

How would you scale Strategy Pattern to handle 10x the current load? Identify bottlenecks and solutions.

Solution
// Scaling approach:
// 1. Load balancing
// 2. Database sharding/replication
// 3. Cache layer (Redis)
// 4. CDN for static assets
// 5. Async processing (queues)
// 6. Microservices decomposition
Strategy Pattern Failure Modes

Analyze potential failure modes for Strategy Pattern and design mitigation strategies.

Solution
// Failure mitigation:
// 1. Redundancy (multi-AZ)
// 2. Circuit breakers
// 3. Retry with backoff
// 4. Dead letter queues
// 5. Health checks
// 6. Graceful degradation

Quiz

1. What does the Strategy pattern allow?

Question 1 options

2. How is the strategy injected into the context?

Question 2 options

3. What principle does Strategy pattern help follow?

Question 3 options

4. What replaces if/else chains with Strategy pattern?

Question 4 options

5. When should you use Strategy pattern?

Question 5 options

Flashcards

Question

What is the Strategy pattern?

Answer

Defines a family of algorithms, encapsulates each one, and makes them interchangeable. Allows algorithm selection at runtime through composition.

Question

What are the components of Strategy pattern?

Answer

Strategy interface (defines algorithm), Concrete strategies (implement algorithms), Context (uses strategy via composition).

Question

How is strategy swapped at runtime?

Answer

Through setter injection on the context: context.setStrategy(newStrategy). Or through a strategy registry/map.

Question

What does Strategy pattern replace?

Answer

Complex if/else or switch chains for algorithm selection. Instead of conditionals, use polymorphism through strategy objects.

Question

What principle does Strategy follow?

Answer

Open-Closed Principle: add new algorithms by adding new strategy classes, without modifying existing context code.

Revision Notes

Key Takeaways

  • 1.Strategy pattern defines a family of interchangeable algorithms
  • 2.Strategies are injected into context via constructor or setter
  • 3.Strategy enables Open-Closed Principle: add algorithms without modifying context
  • 4.Replaces complex if/else chains with polymorphic strategy objects
  • 5.Runtime strategy swapping enables flexible behavior

Interview Tips

  • Show Strategy pattern when discussing algorithm flexibility
  • Explain how Strategy eliminates conditional logic
  • Demonstrate runtime strategy swapping in your design
  • Discuss how Strategy supports testing in isolation

Cheat Sheet

Strategy Pattern - Cheat Sheet

Structure:

Context ──uses──▶ Strategy (interface)
                     │
            ┌────────┴────────┐
         ConcreteA        ConcreteB

Key Points:

  • Strategy interface defines algorithm
  • Concrete strategies implement algorithms
  • Context uses strategy via composition
  • Swapped at runtime via setter

Benefits:

  • OCP: Add new strategies without modifying context
  • No if/else chains
  • Runtime flexibility
  • Testable in isolation

Use Cases:

  • Payment processing
  • Pricing algorithms
  • Sorting algorithms
  • Notification delivery
  • Route calculation

Implementation:

  1. Define strategy interface
  2. Implement concrete strategies
  3. Context holds strategy reference
  4. Inject strategy via constructor/setter