BehavioralverifiedVerified

Chain of Responsibility

Passes a request along a chain of handlers, where each handler decides to process it or pass it to the next handler in the chain.

Coming Soon

errorThe Challenge

When a request could be handled by multiple objects, hardcoding the handler creates tight coupling. Adding new handlers requires modifying existing code, violating the Open/Closed Principle. The sender shouldn’t need to know which object will ultimately handle the request.

check_circleThe Solution

Create a chain of handler objects, each with a reference to the next handler. When a request arrives, the first handler either processes it or forwards it. This decouples senders from receivers and allows dynamic chain composition at runtime.

Architecture Overview

hourglass_empty

Rendering diagram...

Implementation

interface Request {
  type: string;
  payload: unknown;
}

abstract class Handler {
  private next: Handler | null = null;

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

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

class AuthHandler extends Handler {
  handle(request: Request): string | null {
    if (request.type === "auth") {
      return "Handled by AuthHandler";
    }
    return super.handle(request);
  }
}

class ValidationHandler extends Handler {
  handle(request: Request): string | null {
    if (request.type === "validate") {
      return "Handled by ValidationHandler";
    }
    return super.handle(request);
  }
}

class LoggingHandler extends Handler {
  handle(request: Request): string | null {
    console.log(`Logging: ${request.type}`);
    return super.handle(request);
  }
}

// Build the chain
const auth = new AuthHandler();
const validation = new ValidationHandler();
const logging = new LoggingHandler();

logging.setNext(auth).setNext(validation);

// Process requests
logging.handle({ type: "auth", payload: {} });
logging.handle({ type: "validate", payload: {} });
Compiled with TypeScript 5.6
lightbulb

Real-World Analogy

Like a customer support escalation: your call starts with a front-line agent. If they can’t resolve it, they transfer you to a specialist. If the specialist can’t help, it goes to a manager. Each level either handles it or passes it up the chain.