Strategy Design Pattern

What is a Strategy Design Pattern

The Strategy pattern is useful when there is a set of related algorithms and a client object needs to be able to dynamically pick and choose an algorithm from this set that suits its current need.

In software development, the Strategy design pattern allows for the dynamic selection and interchangeability of algorithms at runtime.

The Strategy design pattern is a behavioral design pattern that allows you to define a family of algorithms, encapsulate each one of them, and make them interchangeable at runtime. It enables the client to choose the appropriate algorithm without tightly coupling the client code to specific implementations.

The Strategy pattern suggests keeping the implementation of each of the algorithms in a separate class. Each such algorithm encapsulated in a separate class is referred to as a strategy. An object that uses a Strategy object is often referred to as a context object.

Explanation

Strategy pattern is used when we have multiple algorithms for a specific task and client decides the actual implementation to be used at runtime. Strategy pattern is also known as Policy Pattern. We define multiple algorithms and let client application pass the algorithm to be used as a parameter.

One of the best example of this pattern is Collections.sort () method that takes Comparator parameter. Based on the different implementations of Comparator interfaces, the Objects are getting sorted in different ways.

Key Features of the Strategy Design Pattern:

  1. Context: The context represents the object that interacts with the strategy objects. It contains a reference to the current strategy and uses it to perform the desired operation.
  2. Strategy Interface / Abstract class : The strategy interface or abstract class defines the common methods that encapsulate different algorithms. It provides a contract for all concrete strategy implementations.
  3. Concrete Strategies: Concrete strategy classes implement the strategy interface or extend the strategy abstract class. Each concrete strategy encapsulates a specific algorithm.
  4. Client: The client code creates an instance of the context and sets the desired strategy. It uses the context to perform operations without needing to know the specifics of the strategy.

NOTE –

The strategy pattern is one way that composition can be used as an alternative to subclassing. Rather than providing different behaviors via subclasses overriding methods in super classes, the strategy pattern allows different behaviors to be placed in Concrete Strategy classes which share the common Strategy interface.

A Context object contains a reference to a Strategy. By changing the Context’s Strategy, different behaviors can be obtained.

Examples

  • java.util.Comparator#compare ()
  • javax.servlet.http.HttpServlet
  • javax.servlet.Filter#doFilter ()

Implementation

Create the Strategy interface

// Strategy interface
interface SortingStrategy {
    void sort(int[] array);
}

Implement concrete sorting strategies

// ConcreteStrategyA
class BubbleSort implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implementation of Bubble Sort
        System.out.println("Sorting using Bubble Sort");
    }
}

// ConcreteStrategyB
class MergeSort implements SortingStrategy {
    @Override
    public void sort(int[] array) {
        // Implementation of Merge Sort
        System.out.println("Sorting using Merge Sort");
    }
}

Create a Context class that will use the strategies

// Context class
class SortingContext {
    // Context contains a reference to the strategy
    private SortingStrategy strategy;

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

    public void sortArray(int[] array) {
        strategy.sort(array);
    }
}

Client code / Demo

public class Main {
    public static void main(String[] args) {
        int[] data = {5, 2, 7, 1, 3};

        SortingContext context = new SortingContext();

        // Use BubbleSort
        context.setStrategy(new BubbleSort());
        context.sortArray(data);

        // Use MergeSort
        context.setStrategy(new MergeSort());
        context.sortArray(data);
    }
}

Output :

Sorting using Bubble Sort
Sorting using Merge Sort

In this example, we have two concrete sorting strategies, BubbleSort and MergeSort, that implement the SortingStrategy interface. The SortingContext class is the context that uses these sorting strategies. At runtime, you can change the sorting strategy used by the context by calling setStrategy() with the appropriate concrete strategy.

The Strategy pattern provides a flexible way to define interchangeable algorithms, making the code more maintainable and scalable. It is often used in scenarios where different variations of an algorithm need to be supported or when you want to allow the client to choose a specific behavior dynamically.

In Java, the Strategy pattern can be applied in various scenarios where different algorithms need to be selected and used dynamically.


Use cases

Use the Strategy pattern when:

  • Many related classes differ only in their behavior. Strategies provide a way to configure a class with one of many behaviors.
  • You need different variants of an algorithm. For example, you might define algorithms
    reflecting different space/time trade-offs. Strategies can be used when these variants are implemented as a class hierarchy of algorithms.
  • An algorithm uses data that clients shouldn’t know about. Use the Strategy pattern to
    avoid exposing complex, algorithm-specific data structures.
  • A class defines many behaviors, and these appear as multiple conditional statements in
    its operations. Instead of many conditionals, move related conditional branches into their own Strategy class.