Newsletter sign-up
View all newsletters

Sign up for our technology specific newsletters.

Enterprise Java
Email Address:

The Chain of Responsibility pattern's pitfalls and improvements

Don't call the next chain node in your concrete chain class anymore

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone

Recently I wrote two Java programs (for Microsoft Windows OS) that must catch global keyboard events generated by other applications concurrently running on the same desktop. Microsoft provides a way to do that by registering the programs as a global keyboard hook listener. Coding did not take long, but debugging did. The two programs seemed to work fine when tested separately, but failed when tested together. Further tests revealed that when the two programs ran together, the program that launched first was always unable to catch the global key events, but the application launched later worked just fine.

I resolved the mystery after reading the Microsoft documentation. The code that registers the program itself as a hook listener was missing the CallNextHookEx() call required by the hook framework. The documentation reads that each hook listener is added to a hook chain in the order of startup; the last listener started will be on the top. Events are sent to the first listener in the chain. To allow all listeners to receive events, each listener must make the CallNextHookEx() call to relay the events to the listener next to it. If any listener forgets to do so, the subsequent listeners will not get the events; as a result, their designed functions will not work. That was the exact reason why my second program worked but the first didn't!

The mystery was solved, but I was unhappy with the hook framework. First, it requires me to "remember" to insert the CallNextHookEx() method call into my code. Second, my program could disable other programs and vise versa. Why does that happen? Because Microsoft implemented the global hook framework following exactly the classic Chain of Responsibility (CoR) pattern defined by the Gang of Four (GoF).

In this article, I discuss the loophole of the CoR implementation suggested by GoF and propose a solution to it. That may help you avoid the same problem when you create your own CoR framework.

Classic CoR

The classic CoR pattern defined by GoF in Design Patterns:

"Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it."


Figure 1 illustrates the class diagram.

Figure 1. CoR class diagram

A typical object structure might look like Figure 2.

Figure 2. CoR object structure

From the above illustrations, we can summarize that:

  • Multiple handlers may be able to handle a request
  • Only one handler actually handles the request
  • The requester knows only a reference to one handler
  • The requester doesn't know how many handlers are able to handle its request
  • The requester doesn't know which handler handled its request
  • The requester doesn't have any control over the handlers
  • The handlers could be specified dynamically
  • Changing the handlers list will not affect the requester's code


The code segments below demonstrate the difference between requester code that uses CoR and requester code that doesn't.

  • Digg
  • Reddit
  • SlashDot
  • Stumble
  • del.icio.us
  • Technorati
  • dzone
Comments (1)
Login
Forgot your account info?

How long does the object (sub-class) stay in memory?By Anonymous on July 2, 2009, 10:36 pmI am not big fan of CoR in java/c++. The article about decoupling the logic is well written. However, my question is, does the current object still remain in stack/memory...

Reply | Read entire comment

View all comments

Add comment
Anonymous comments subject to approval. Register here for member benefits.
Have a JavaWorld account? Log in here. Register now for a free account.
Resources