I believe most developers have seen code like this:
At first glance, there is nothing wrong with this implementation, it looks pretty clean.
However, suppose we want to add support for DELETE, PATCH, and HEAD HTTP methods. For this, we need to implement the handling logic for each method in this class and include them in the switch block. This is a pure violation of the Open-Closed Principle which states: Software entities should be open for extension, but closed for modification. From my own experience, I have seen some switch statements that were hundreds of lines long and I assure you that such code is messy and hard to test. It would be nice if we could add support for new HTTP methods without touching the existing logic. This is where the Strategy Design pattern comes in to help us.
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.
Let us try to apply this pattern and reimplement our RequestReceiver class. First of all, we need to define a new abstraction that will be responsible for handling individual requests.
After creating new abstractions, there are several ways to use them and I will show a couple of them:
Use Map for storing strategies
Use a dedicated registry for storing strategies
Implementation using Map
We need to populate our Map with strategies and for this, we create a configuration class.
Implementation using dedicated registry
Let us implement a registry for RequestHandlers:
Final implementation of RequestReceiver:
After refactoring, both approaches make our design isolated and at the same time open for extensions, and now we can easily add a new implementation for the DELETE method, and there is no need to change a single line of existing code:
In this article, we have explained the strategy pattern, and also demonstrated how we can implement it in Spring Boot Application.