At Qualyteam, we are continuously improving. Therefore, we love code refactoring. Identifying problems and improvement opportunities in code is an important skill every developer should have. This week I was reviewing code that had a small change in a legacy code base method. It was a small, long forgotten piece of code. We usually balance between the importance of the touched code and the quality it must have. If it’s something that we know that is barely going to be touched in the future, we just let it go and move forward to something our clients are really going to care about. But I wanted to play around. And to have something to write about.
The Code in question
The touched code is a 10 year old Webforms method that returns a CSS class name based on some parameters. I abstracted away the ASP.NET stuff and created some pseudo classes so you can focus on the subject, the
GetClass method. Don’t bother about the code details, just focus on the method structure, specially the
I wanted to make this code more meaningful. You can notice that given some local variables created from the method parameters and some class properties (lines 9 to 13), which we wil call “request”, the code passes through a chain of conditional statements, which we will call “rules”, the first one being
if(hasEvaluation) . This rule has the priority on the chain. If it can’t deal with it’s concerning slice of the request
(evaluation), it passes the handling responsibility for returning the correct string to the next rule in the chain. The next rule gets another slice of the request (
hasEffectiveness) and deals with it or passes the request to the next rule. So:
Given a request, a rule can choose either to handle the result, or pass this responsibility to the next rule.
There’s a design pattern for that.
Meet the Chain of Responsibility
The chain-of-responsibility pattern is a design pattern consisting of a source of command objects and a series of processing objects. Each processing object contains logic that defines the types of command objects that it can handle; the rest are passed to the next processing object in the chain.
Chain of Responsibility is a behavioral design pattern that lets you pass requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain.
Looks like what we need, right? But how would we implement this? Well, since it’s a Gang of Four’s, well documented, 30 years old design pattern, there are already a lot of examples out there! Here’s the UML diagram:
So we must create an abstract handler.
The abstract handler
SetNextmethod will be responsible for setting the next handler on the chain.
Each rule will extend this handler and override the Handle method and decide if it should handle the request, or pass it to the next handler.
The abstract class Handler method calls the next handler Handle.
We don’t have a request object yet. Let’s create it. It’s the object that is going to be passed through the chain. It must contain all the data required by the handlers. In our case, it’s just a Data Transfer Object (DTO) that stores those
GetClass local variables it created at lines 9 to 13:
GetClass method looks like this:
Before moving on, we should get rid of these repeating hardcoded strings, so our code responds easier to future changes by storing the string values in a single place. Let’s create a label class with some static factory methods :
Now we know that our chain of responsibility should handle a
Request and return a
Label . Let’s create our abstract handler based on that UML diagram:
Runmethod is going to be overridden by each rule, which will decide if they should either yield the
Labelto the client or delegate it to the next rule.
SetNext method will not be overridden, but will be used in client code to set the chain in the right rule precedence order. It returns the next rule so we can set the chain using a fluent API. Now let’s create our first rule.
If you remember from the
GetClass method, this is the first one:
We need to create a class that inherits from the abstract
RuleHandler , overrides its
Run method and decides if it should return the proper Label or pass the request to the next handler.
Based on the stuff the conditional statement is checking, I’m going to call the rule
So, given the request, the rule checks if it should yield the result or delegate it to the next handler. This is the drill, and the next rules are going to follow the same structure. But let’s make another one just to get used to it. The next rule in the chain is:
I’m going to call it
I’m going to skip the creation of the
CriteriaEvaluated rules, so we can go straight to our client code.
Now we have a bunch of rules. We need to set the precedence of them, run the chain, and return the result.
We’re going to use the
SetNext method to assemble the chain, respecting the rules precedence. Then we are going to
Run the chain, and return the result. The client API surface is now so simple, that I’m going to show the final
GetClass method after the refactoring:
So we set the chain using the abstract RuleHandler’s
SetNext method. It sets the next rule to the current rule, so when we call
Run we run the chain in the set order. It returns next rule, so we can set the chain… chaining methods!
It’s way more clean than the old code right? Take a look at it again:
The client code is cleaner, but we created some boilerplate code, like the abstract
RuleHandler . This abstract class can’t be reused, since it returns and handles only the types we needed for this particular use case(
Label ). We can reduce the amount of boilerplate code used to create a Chain of Responsibility by using C# Generics.
Now we can reuse this generic abstract rule handler in other chains. We just need to specify the types when creating a rule:
Kinda over-the-top? Yeah, I just wanted to show a real world example of a design pattern use, because sometimes everything seems so abstract and academic. But there are plenty of other interesting use cases, like tax processing, ordering pipelines, and you’re probably using something similar like an API middleware. I have a login pipeline simulation in an open source repository here.
The Chain of Responsibility has another cool feature: It’s composable. You could reorder the chain’s rules precedence based on run time conditions. Pretty flexible right?
If you use an object oriented language like C#, PHP or Java it’s nice to play with some Design Patterns, because sometimes you can come up with an elegant solution to a hard solving problem, or at least have a lot of fun!