← Back to Home

Chain of Responsibility Pattern

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request.

What is it?

The Chain of Responsibility pattern chains handler objects and passes a request along the chain until an object handles it.

Example

interface Handler {
  setNext(handler: Handler): Handler;
  handle(request: string): string | null;
}

abstract class AbstractHandler implements Handler {
  private nextHandler: Handler | null = null;

  setNext(handler: Handler): Handler {
    this.nextHandler = handler;
    return handler;
  }

  handle(request: string): string | null {
    if (this.nextHandler) {
      return this.nextHandler.handle(request);
    }
    return null;
  }
}

class AuthHandler extends AbstractHandler {
  handle(request: string): string | null {
    if (request === 'auth') {
      return '✅ Authentication successful';
    }
    return super.handle(request);
  }
}

class LoggingHandler extends AbstractHandler {
  handle(request: string): string | null {
    if (request === 'log') {
      return '📋 Logged request';
    }
    return super.handle(request);
  }
}

class DataHandler extends AbstractHandler {
  handle(request: string): string | null {
    if (request === 'data') {
      return '📦 Data processed';
    }
    return super.handle(request);
  }
}

// Setup
const auth = new AuthHandler();
const log = new LoggingHandler();
auth.setNext(log);
const data = new DataHandler();
log.setNext(data);

console.log(auth.handle('auth'));
console.log(auth.handle('log'));
console.log(auth.handle('data'));
console.log(auth.handle('unknown'));

Common Uses

  • Event bubbling and capturing
  • Request processing pipelines
  • UI frameworks and middleware

When to Use

  • When multiple objects can handle a request
  • To decouple sender and receiver

Caution

  • Can complicate debugging and tracing
  • Order of handlers matters