Strategy Pattern
What is it and how to use it to improve your code.
What is it?
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:
Now let's add our implementations:
All that's left is to use the strategy.
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 will start with the strategies:
The interface remains the same and the implementations receive the @Component
annotation.
Now let's move on to the verification service.
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.
Now let's modify the service to use the library.
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.
Last updated