According to Wikipedia, the strategy pattern is a behavioral software design pattern that enables selecting an algorithm at runtime. Instead of implementing a single algorithm directly, code receives run-time instructions as to which in a family of algorithms to use.
In simple words, the strategy pattern is used to specify how something should be done by providing a specific algorithm.
For example, a strategy for payment could be Credit Card, PayPal, or any other payment provider.
Why should we use it?
The Strategy Pattern defines a family of algorithms, encapsulates each one, and makes them interchangeable. Strategy lets the algorithm vary independently from clients that use it (source).
In short, it makes our code cleaner, easier to maintain, and reusable.
The Strategy Pattern in Code
Implementations of the pattern consist of an interface defining the strategy, multiple concrete implementations of the strategy and a context using the strategy.
Code Example
Let's look at the following simplified scenario:
We have an application with users and we need to send them verification codes for 2FA.
The application supports multiple communication options for receiving the verification code: Email, SMS, Notifications...
Each user selects its preferred communication method.
We will start by implementing the strategy pattern without Spring and the library. First we will define our strategy interface:
We can see how the code is clean and easy to maintain. Adding a new communication method would be easy and will not need to change existing code other than adding it to the map of strategies.
Code Example WITHOUT the library
Let's revise the previous example for a regular Spring Boot implementation.
When using the strategy pattern in a Spring Boot application the context and strategy implementations are usually Spring components.
We need to add the strategy implementations to the constructor and build the map manually. That's no fun!
Code Example WITH the library
The entire objective of the library is to make our life easier and the code cleaner and less bug prone. It does it by simply building the strategy map automatically.
We will start by modifying the strategy interface.
As you can see we have added a new field method with the annotation @ComponentMapKey. This informs the library which field is the key for the strategy map.
Let's update the implementations according to the modified interface.
That's it! All we had to do is to add the @ComponentMap annotation to the strategy map and voila! The map is built automatically from the components. No boiler-plate code. To add a new strategy all you need to do is to create a new implementation and it will be "magically" added to all relevant strategy maps.