Skip to main content

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.