I’ve spent the last two weeks reading another refactoring famous reference. After Refactoring, I decided to read Refactoring to Patterns, which is also very good, and today I’ll share one sample of book’s refactoring catalog: Replace Conditional Dispatcher with Command. In this example, you will be able to see some of book’s approach and how this practice improves code quality.
“Conditional logic is used to dispatch requests and execute actions. Create a Command for each action. Store the Commands in a collection and replace the conditional logic with code to fetch and execute Commands.”
A lot of systems receive and manipulate requests, which in some cases are processed by conditional statements. There is no problem if your conditional mecanisn is small and treats just a few number of requests. However, if your if-else’s start growing, it’s time to search for betters solutions. A good option is change from conditional statements to the Command pattern, providing runtime flexibility and avoiding inflated code.
To implement the pattern, you just separate each block of the conditional dispatcher in a separated command class with a common execute method responsable for executing a specific encapsulated logic. So, besides of calling different routines depending on the received request, you will now just call the excute method for all of them.
- provide a simple mecanism to execute different behaviors in a common way.
- allow runtime changes in which requests are manipulated and how they are manipulated.
- easy implementation with trivial code.
- complicates a project when a conditional statement it’s enough.
Now, let’s examine a real-life example. Imagine you have the code below:
In this example, the RequestHandler class is responsable for manipulating requests depending on its actionName parameter in a big conditional statement. It isn’t a good approach at all, so let’s start refactoring it. The first step is apply extract method on each conditional body. This step will result in the following code.
I compile and test to make sure that I didn’t break anything.
The next step creates concrete commands for each existing if-else block. So, we will add two new classes to the project: ErrorHandler and SuccessHandler, and later apply move method to the existing methods in the RequestHandler class. That’s is the result.
Again I compile and test.
With the concrete commands created, it’s time to create the command interface. Note that both commands have different methods name and we still use the conditional statement to instantiate the correct concrete command. Let’s use a Handler interface with an execute method to manipulate the requests. In addition I used move method in getMessage and preparedEmail because, at this moment, they are specific to its respectively concrete handler. Here is how the code looks like after this changes.
Compile and test one more time.
To complete this refactor we must call Handler.execute() for all requests, independently of its type. This is possible by creating a factory method, which returns the correct handler depending on the request’s actionName. However, the conditional statement will continue making part of the code. So, I’ll use a different solution. To define which concrete handler instatiate, I will make use of a Map of actionName, mapping the name of the request to the correct handler. The final result is shown below.
Now, the code is much more clean, extensible and readable.