Handlers

Quick Profile

Alex Ooi Profile Picture
Hometown: Melbourne, Australia
Specializations: Java, Ruby on Rails
University: Software Engineering & Economics, Melbourne University
High School: VCE, Melbourne High School
Links:
 

Popular Articles

Sunday, August 28, 2011

The other day I yet again found myself using the Chain of Responsibility pattern to refactor some code that I had written a little earlier. It is one of my favorite patterns, primarily because it allows us to break a large piece of work into much smaller pieces which are far more easily re-used and unit tested.

I'm not going to describe the pattern itself as there is probably quite a lot of literature out there already. After all, it is one of the GoF patterns! :) The wiki page that I've linked to gives quite a good and practical description of it. Instead, I'm just going to quickly describe the recent scenario that popped up where I found the pattern useful.

Rushed PoC

We had rushed through a lot of coding to get a PoC out the door in 3 weeks. I wouldn't say it was the most ugly code that I've written, but certainly we didn't feel it was effective to write test cases (since the code was changing dramatically every day) and we didn't want to spend time refactoring until we knew what we were building would actually work! So, we certainly weren't using any design patterns initially.

However, after finishing the PoC I had a bit of time to go back and take stock of what we'd done. It was then that I found this particular piece of code which handled the servicing of a submitted Application (class/method names have been changed to protect the identity of their previous owners :P ... hahaha ):

public class Processor
{
    private StateManager manager;

    public void doSomething(BusinessApplication application) 
    {
        manager.start(application);

        manager.service(application);

        manager.notify(application);

        manager.queue(application);

        manager.end(application);

    }
}

So whats wrong?

I wouldn't say anything was particularly "horrible" about that piece of code. However, something is definitely odd. There were a few problems:

  1. The StateManager is probably doing too much crap. Although the code had managed to keep the knowledge of the workflow out of the StateManager, the StateManager itself still knows about too much stuff. It has to know how to perform all those 5 business tasks. If more tasks were to be added in the future to this workflow then the StateManager would get bigger and bigger
  2. The method signature of all the methods on the StateManager are exactly the same. Except for the name of the method of course :P Classic hint to introduce some sort of polymorphism!

Refactor!

So i decided that a "chain of responsibility", or Handlers, should be introduced. I introduced a common interface:

public interface ApplicationHandler
{
    void handle(BusinessApplication application);
}

... 5 individual implementations of this interface which dealt with the specific functionality it was concerned with:

public interface StartProcessingApplicationHandler 
                         implements ApplicationHandler
{
    // declare the specific dependencies of this handler

    public StartProcessingApplicationHandler( ....... ) 
    {
        // assign the specific dependencies of this handler
    }

    void handle(BusinessApplication application) 
    {
        // business logic for handling the start of the application
    }
}

public interface ServiceApplicationHandler 
                         implements ApplicationHandler
{
    // declare the specific dependencies of this handler

    public ServiceApplicationHandler( ....... ) 
    {
        // assign the specific dependencies of this handler
    }

    void handle(BusinessApplication application) 
    {
        // business logic for handling the servicing of the application
    }
}

//
// you get the idea....
//

... and to hook up these handlers in a pre-defined way to the Processor, I introduced a Factory for creating these applications in the correct order

public interface ApplicationHandlersFactory
{
    List<ApplicationHandler> getHandlers() 
    {
        return Arrays.asList(
          new StartProcessingApplicationHandler( .... ),
          new ServiceApplicationHandler( .... )
          // and so on and so forth ....
        );
    }
}

One other good side-effect of breaking the workflow into smaller units of work is that they can be hooked up differently to alter the workflow, either by altering this factory or creating different factories. For example, if we wanted to ignore queueing and notification in another part of the system then it would be as simple as creating another factory which creates a chain of the following handlers: "starts -> services -> ends". The code for the handlers need not change, and need not know about these different workflows. This pattern has allowed us to make our code much more re-usable :)

The Result

The result was that the whole workflow was broken down into much smaller, more modular pieces that were far easier to unit test. Also, since each handler required different dependencies (pumped in through their constructor), this meant that a handler which processed the "start" of the Application did not have to be cluttered with dependencies that only a "service" handler required. And so on and so forth...

Finally, the Processor was refactored to this:

public class Processor
{
    private ApplicationHandlersFactory factory;

    public void doSomething(BusinessApplication application) 
    {
        for( ApplicationHandler handler : factory.getHandlers() )
        {
            handler.handle(application);
        }
    }
}

So there you have it. A recent practical example of where the "chain of responsibility" pattern helped to break down a workflow into smaller parts. The benefits of which were:

  1. Individual handlers responsible for only one responsibility. The code for performing one unit of work on an application need not have any idea of anything that came before it or after it
  2. Reducing class dependencies in each handler
  3. More unit testable code
  4. Flexibility to introduce more handlers in the future whilst minimizing impact to existing handlers
  5. Flexibility to change the workflow (either by introducing different "Factories" or by changing the existing one) without having to deal with the actual code for handling each unit of work

Comments ...

Had a quick look at your example & wikipedia. I think there's a bit of difference in the way the client code invoke the handler.

I was thinking more like this:

https://github.com/alexwibowo/Pattern-Studio/blob/master/src/test/java/org/isolution/chainOfResponsibility/ChainOfResponsibilityClientTest.java

i.e. the client is not aware that there are a line of handlers.
Posted by Ultimate Batpig on Tuesday, September 13, 2011 at 05:56 AM
Yes, I thought about this. However, I felt that creating that extra class to hide the chaining from the caller would require me creating that extra class without any real practical difference. So i decided to just keep the loop in the caller.
Posted by Alex Ooi on Tuesday, September 13, 2011 at 04:35 PM
Nigger, what you have isn't CoR. You just have a bunch of wired commands ( from command pattern)
Posted by Tester on Wednesday, September 14, 2011 at 11:10 PM
sort off commands ... but i wouldn't say its pure command pattern either

anyway, the exact type of pattern that I described academic... the point is the polymorphism and modularity of the damn thing
Posted by Alex Ooi on Thursday, September 15, 2011 at 04:20 AM

Add a Comment

*
*
You must answer the following simple maths question before your comment will be accepted.
*