JavaWorld
addict
Reged: 06/20/03
Posts: 482
|
|
The Chain of Responsibility pattern
|
_aXe_
stranger
Reged: 06/24/03
Posts: 2
Loc: USA
|
|
Your work is good... but a pattern that has been used for years can't be the way it is for nothing...
Look at this one here: TheServerSide's reply
|
Mickael
Unregistered
|
|
I can't see why the proposed solution can't handle the code sample below given by _aXe_:
long startTime = System.currentTimeMillis(); chain.proceed(request, response); log.info("children took " + (System.currentTimeMillis() - startTime) + "ms to complete");
The code above is just the usage of the chain, not a definition of a chain. The way to use a chain is same for all kinds of chain.
|
TomJava
Unregistered
|
|
Excellent article. I had implemented a similar workaround for an existing CoR pattern. However, that pattern does not violate a principle of object-oriented design. Other patterns such as Composite pattern would also violate that principle. Thanks. Tom
|
Chuck_Daniels
stranger
Reged: 08/19/04
Posts: 1
|
|
I agree with the "flaw" you point out in the classic CoR pattern. However, I don't quite agree with your implemented solution. You have lumped two distinct concepts into a single implementation class. That is, your new "chain" class represents both the "chain" as well as the "nodes" that are chained together. I suggest you separate these into distinct classes since they are conceptually distinct.
For example, a Filter is distinct from a FilterChain in J2EE, which is conceptually appropriate even though their implementations may be considered flawed, as you suggest. There is no need to lump these two distinct classes together into a single class in order to fix their implementation flaws.
As an outline, the separation might look similar to the following, which focuses merely on chain processing and ignores chain construction (this is a modification to the ClassChain implementation in the article):
Code:
public class Chain { // Ignoring how this gets populated private List nodes;
public void start(ARequest request) { Iterator i = nodes.iterator(); boolean handled = false;
while (i.hasNext() && !handled) { handled = ((Node) i.next()).handle(request); } } }
interface Node { boolean handle(ARequest request); }
|
MattH
Unregistered
|
|
I'm a tech manager, not a developer. But appreciation for OOD principles is strong, so this was an appealing article for me. Also big fan of the author who did awesome work on our Fortune 50 project.
Nice article, Mike.
|
Anonymous
Unregistered
|
|
The simplicity of your Command pattern based solution shows how bogus the Chain of Responsibility pattern is , it also makes it very easy to see if anything actually handled the event, very important for logging & client feedback!
IMHO the Chain of Responsibility pattern is just a lame attempt to re-invent the linked list, and pollutes the handler (command) objects with a link e.g. you can't share the handler object with other chains! 
|
Anonymous
Unregistered
|
|
Eccelent article! JAX-RPC defines its handler chain using the same approach suggested by this article.
|
michael huang
Unregistered
|
|
Add three more motheds in the chain base class:
protected abstract void before(); protected abstract void after(); protected abstract void onAException(AException e);
in start(): public final void start(ARequest request) { this.before(); try{ this.handle(request); }catch(AException e){ this.onAException(e); //loop through prevousNodes, call onAException() on them. } this.after(); if (next != null) next.start(request); }
This way, the individual nodes get chance to do whatever they want to do before and after handle(). In addition, when an exception hanppens, all executed nodes get notified.
|
ejboy
Unregistered
|
|
Quote:
Your work is good... but a pattern that has been used for years can't be the way it is for nothing...
Agreed. The original CoR is more powerful and extensible. It allows to implement interceptors, e.g. open DB connection before calling successor and close it on sucessor completion. Original handlers may even run successors in a separate thread for some reasons;). It also allows to catch exceptions in a handler specific way. Moreover this restricted solution could be easily derived from the original pattern, by subclassing from the Handler with specific template method, e.g. Code:
public abstract class EasyHandler { public void handle() { if( notHandled ) { next.handle(); } }
public abstract boolean execute();
}
Regards, Fyodor Kupolov
|
GKR
stranger
Reged: 12/23/06
Posts: 1
|
|
Even though I see this at this time but I believe it is never late in expressing views.
"The fundamental flaw here is that the chain execution decision-making, which is not the business of subclasses, is coupled with request-handling in the subclasses. That violates a principle of object-oriented design: an object should mind only its own business. By letting a subclass make the decision, you introduce extra burden on it and the possibility for error."
I believe this argument is fundamentally flawed. First of all, in an object-oriented world, everything is an object which perfectly fits for java. A subclass or a base class whatever you see is code as a programmer not as a object thinker. But in runtime when an object manifests it's state, it might be made up of (inherited) base structure/behavior (just to remind, all classes in java are inherited from base Object). So, subclass minding it's own business does not make sense in object-oriented approach. The author is confusing between two distinct issues. One is applying chain of responsibility pattern for the business/functionality. Second is how to make the programmer bind into a contract of not ommiting/forgetting. The classic GoF pattern says that the a request handling chain continues until the one handler which handles it. This means ones handled it will stop. However, there is no order of finding it. Client does not know which handler exactly handles etc etc.... If every handler in the chain needs to handle then it will be like original java event handling mechanism.... Also, Chain of Responsiblity pattern does not dictate how you enforce the programmer to maintain chain... As alwasy architects mention...to solve a problem one pattern does not completely provides solution...instead it would be combination of patterns... One could easily fix the programmers mistakes with author's solution as we all know by a interface contract and one base class (I say broker/contact-point to client w.r.t request handling) handling chain control.
|