Chain of Responsibility
Overview
Pass a request along a chain of handlers until one handles it.
When to use
- Multiple handlers can process a request.
- You want to decouple sender from receiver.
- You want to assemble processing pipelines, such as middleware or validation steps.
Java example
abstract class Handler {
private Handler next;
Handler link(Handler next) {
this.next = next;
return next;
}
boolean handle(String msg) {
return next != null && next.handle(msg);
}
}
class ErrorHandler extends Handler {
boolean handle(String msg) {
if (msg.contains("ERROR")) {
return true;
}
return super.handle(msg);
}
}
class FallbackHandler extends Handler {
boolean handle(String msg) {
return true;
}
}
TypeScript example
abstract class Handler {
private next?: Handler;
link(next: Handler): Handler {
this.next = next;
return next;
}
handle(msg: string): boolean {
return this.next?.handle(msg) ?? false;
}
}
class ErrorHandler extends Handler {
handle(msg: string): boolean {
if (msg.includes('ERROR')) {
return true;
}
return super.handle(msg);
}
}
class FallbackHandler extends Handler {
handle(_msg: string): boolean {
return true;
}
}
Pros and cons
Pros:
- Flexible handler composition.
- Reduces coupling.
Cons:
- Can be hard to debug.
- Requests may go unhandled.
Common pitfalls
- Not defining a default handler when one is required.
- Long chains with unclear responsibility boundaries.