Welcome to the sixth instalment of the Design Patterns series. If you are curious about the previous topic, State Patterns, then just read the last article. This time, we will look at the Chain Pattern.
This pattern works perfectly when we have a series of checks or actions that are executed one after the other. Validation is a great example of this, and this is the one we will use. In this example we are trying to check if the order is valid. There are some criteria that we need to check to see the result of the validation. We will look at two approaches to this and compare them.
The code presented in this post can be found at: https://github.com/Nivo1985/net_patterns. The projects in the solution correspond to the pattern's names.
As always, we will create a simple application that checks if the order object is valid. There will be three conditions that determine this factor. We will start with a code style that is fast to write, but that is also its only advantage. Our goal is to create a better validation mechanism. By better, I mean well designed, easy to read and easy to maintain. The tool that will help us do this is the chain pattern.
The old way
The aim is to check the order. Let us begin by seeing what order is.
This is only a simple class. It contains three fields. These fields describe the name of the order, the barcode and information about the region of the buyer. Nothing really fancy.
The code we want to run is inside the OldWay method.
It is quite straight forward. We create an order which will be a share class in the old and new solution. Then we proceed to validate the order. It takes place within the Process method. Let us take a look at this.
Validation is super easy. However, there are three conditions: The barcode must be valid, the name must not be too short and the buyer must not be from Norway. Why from Norway? Just... because.
Joking aside. This code works correctly. The problem lies in its organisation and reusability. Again, we have an if-drive design. If we can clearly see that there are three distinct and completely independent elements of validation logic. There must be a way to improve this design and make it more agile and reusable. Let us try to achieve this with the help of the chain pattern.
The new way
What are we trying to achieve here? The goal is to change the code so that validation is broken down into individual elements of responsibility. This change, combined with a chain pattern, will greatly improve the validation process.
To do this we need a tool that we will call the Handler. It will allow us to code in chain form. The handler will consist of two elements - an interface and an abstract class.
As we can see, the interface is a generic one. Moreover, the generic type must be a class of some kind. It has two methods known as SetNext and Handle. This interface is implemented by the Handler class, which has the same generic design as an interface. It is also abstract and has a property that contains a reference to the next chain handler.
The implementations of the methods are quite short. The Handle method executes a handle method of the Next Handler object. With the method SetNext we can build up the chain of handlers by adding the next element to the chain.
This gives us a mechanism for creating a chain and executing elements in that chain. Now we will discuss the elements.
This is no surprise. The validation conditions will form the chain elements. All three are constructed in a similar way and all derive from the Handler class (they have only one method, the Handler method). In all three cases, all this method does is check the validation. If the validation is successful, the process is passed on to the next chain element. That's it, super simple to be honest.
The final part of the solution is to use this new approach in our code. The change of approach will have an impact on the order processing mechanism.
The validation process looks so much better because we can clearly see the elements that make up the process. They are loosely coupled so we can mix and match them as we see fit. Also, each of us can understand what each element does just by seeing its name. That's a triple win, if you ask me.
The use of these two validation methods is identical. The only difference is in the class we need to perform it. The way it is coded, and the result are identical.
This is not only an example of introducing a design pattern into a solution, but also an excellent case study of how code refactoring should be done. And why? Because the front end of the code remains the same. This is an approach that should always be taken when there is an opportunity to do so.
In this case, the user of our solution is not forced to make changes to their code. Yes, I know I have two classes for the process. But I only did that for academic purposes. In a real scenario, I would simply change the original class.
The validation infrastructure got rewritten. From the set of ifs, it morphed into well-organized set of agile classes with a clearly defined goal. The code we have now is much easier to read and maintain. It is also modular. Thanks to it, we can use any combination of validation classes. I would say we have done a good job.
Like any single pattern, it should be used in cases where value can be extracted. If you have ever used it, wait no more and let me know at email@example.com.