Spring Boot Strategy Pattern Example

By Ercan - 25/09/2025 - 0 comments

Design patterns are one of the most valuable tools in a developer’s toolkit. They provide proven solutions to recurring design problems and help us write code that is maintainable, flexible, and easy to extend. One of the most practical patterns in everyday software development is the Strategy Pattern.

In this article, we’ll look at how the Strategy Pattern can be applied in a real-world example using Spring Boot. We will build a simple REST API that takes a piece of text and returns its hash, depending on the algorithm selected by the client. The project is a minimal but effective demonstration of the Strategy Pattern in action.


What is the Strategy Pattern?

The Strategy Pattern is a behavioral design pattern that defines a family of algorithms, encapsulates each one, and makes them interchangeable. The client doesn’t need to know the details of how each algorithm works—it only needs to choose the appropriate strategy at runtime.

In plain words, instead of writing a giant if-else block to handle different algorithms, we separate each algorithm into its own class and let a context object decide which one to use.


The Use Case: Hashing Service

Depending on the use case, you might need to hash data using MD5, SHA-1, SHA-256, or other algorithms. Rather than hardcoding these choices or writing repetitive conditional logic, we can use the Strategy Pattern to keep the implementation clean and extensible.

Our project exposes two APIs:

  1. Get Supported Algorithms – Returns a list of all available hashing algorithms.
  2. Generate Hash – Takes a text input and an algorithm, then returns the hashed value.

Project Structure

Here’s how the project is organized:

  • Controller: Handles API requests (HashController).
  • DTOs: Request and response objects (HashRequest, HashResponse, ExceptionResponse).
  • Service Layer: The context class (HashStrategyContext) delegates to the right hashing strategy.
  • Strategy Interface: HashStrategy defines the contract for all hashing algorithms.
  • Concrete Strategies: Classes like MD5HashStrategy, SHA256HashStrategy, SHA512HashStrategy, etc., each implement the HashStrategy interface.
  • Exception Handling: If a user provides an unsupported algorithm, HashStrategyNotFoundException is thrown and handled by ApiExceptionHandler.

This clean separation of responsibilities makes it easy to add new algorithms in the future. Just implement the HashStrategy interface and register the new class.


The Role of HashStrategyContext

One of the most critical classes in this project is the HashStrategyContext.

This class is responsible for selecting the correct hashing algorithm at runtime. Instead of the service or controller knowing about all possible strategies, the context takes care of finding and applying the correct one.

This makes the system easy to extend: adding a new algorithm requires no modification to existing code—just a new strategy implementation.

Here’s the code:

@Component
@RequiredArgsConstructor
public class HashStrategyContext {

  private final List<HashStrategy> hashStrategyImplementations;

  private final Map<HashType, HashStrategy> strategyMap = new EnumMap<>(HashType.class);

  @PostConstruct
  public void prepareStrategyMap() {
    hashStrategyImplementations.forEach(
        strategy -> strategyMap.put(strategy.getHashType(), strategy));
  }

  public Set<HashType> getSupportedHashTypes() {
    return strategyMap.keySet();
  }

  public String hash(String text, String algorithm) {
    HashType hashType = HashType.fromAlgorithm(algorithm);

    HashStrategy hashStrategy = strategyMap.getOrDefault(hashType, null);

    if (Objects.isNull(hashStrategy)) {
      throw new HashStrategyNotFoundException("Given algorithm is unsupported");
    }

    return hashStrategy.hash(text);
  }

}

As you can see:

  • All available strategies are injected by Spring and stored in a map.
  • The hash method simply looks up the correct strategy by its HashType.
  • If the algorithm is not supported, a clear exception is thrown.

This design keeps the codebase flexible and avoids any large conditional blocks.


Example API Usage

1. Get Supported Algorithms

curl --location 'http://localhost:8080/hash'

Response:

[
  "MD5",
  "SHA-1",
  "SHA-224",
  "SHA-256",
  "SHA-384",
  "SHA-512"
]

2. Generate Hash

curl --location 'http://localhost:8080/hash' \
--header 'Content-Type: application/json' \
--data '{
  "text": "hello world",
  "algorithm": "MD5"
}'

Response:

{
  "hash": "5eb63bbbe01eeed093cb22bb8f5acdc3"
}

Conclusion

The Strategy Pattern is a simple yet powerful design pattern that helps us write clean and extensible code. This Spring Boot project demonstrates how to implement it in a real-world scenario by building a hashing service.

The HashStrategyContext class is the glue that makes everything work seamlessly. By delegating strategy selection to this context, we avoid rigid conditionals and gain a design that is easy to extend in the future.

Whether you’re implementing hashing, payment methods, or sorting algorithms, the Strategy Pattern allows you to keep your code flexible and maintainable.

👉 You can explore the full source code on GitHub:
https://github.com/ercansormaz/strategy-pattern

Tags: spring boot, design pattern, strategy pattern