Skip to content
Behavioral

Chain of Responsibility

Avoid coupling the sender of a request to its receiver by giving more than one object a chance to handle the request. Chain the receiving objects and pass the request along the chain until an object handles it.

Intent

Decouple the sender of a request from its receiver by allowing multiple objects to handle the request in sequence. Each handler decides either to process the request or to pass it along to the next handler in the chain.

Problem

You have a request that could be handled by several different objects, and you do not want the sender to know which specific object will handle it. Hard-coding the handler selection creates tight coupling and makes the system rigid when new handlers need to be added or the order needs to change.

Solution

Define a Handler interface with a method for processing requests and a reference to the next handler. Each ConcreteHandler either processes the request if it can, or forwards it to its successor. The client sends the request to the first handler in the chain without knowing which handler will ultimately process it. Handlers can be reordered, added, or removed without affecting the client.

Participants

  • Handler — defines the interface for handling requests and optionally holds a reference to the next handler
  • BaseHandler — optional abstract class that implements the default chaining behavior (forwarding to the next handler)
  • ConcreteHandler — handles requests it is responsible for; can access its successor to forward unhandled requests
  • Client — initiates the request to the first handler in the chain

Advantages

  • Reduces coupling — the sender does not need to know which handler processes the request
  • Flexible chain composition — handlers can be added, removed, or reordered at runtime
  • Each handler has a single responsibility, following the Single Responsibility Principle
  • A request can be handled by multiple handlers in sequence (middleware-style processing)

Disadvantages

  • No guarantee that a request will be handled — it may fall off the end of the chain
  • Debugging can be difficult because the flow passes through multiple objects
  • Chain configuration must be set up correctly; an incorrect order can produce wrong results
  • Performance may suffer with very long chains, as each handler adds overhead

Real-World Analogy

Calling a company's customer support hotline is a chain of responsibility. Your call goes to a front-line agent first. If they cannot resolve your issue, they escalate it to a specialist. If the specialist cannot help either, it goes to a manager. You, the caller, do not choose who handles your issue — you just enter the chain and each level decides whether to handle or escalate.

Use Cases

  • HTTP middleware pipelines — authentication, logging, CORS, rate limiting, compression
  • Validation chains — each validator checks one rule and passes to the next if valid
  • Support ticket routing — escalate from tier-1 to tier-2 to tier-3
  • Event bubbling in DOM — events propagate from child to parent elements
  • Approval workflows — manager, director, VP each have different authority levels
  • Exception handling — catch blocks form a chain that handles different exception types

Code Examples

An HTTP middleware pipeline where AuthHandler, RateLimitHandler, and LoggingHandler each inspect the request and decide whether to pass it to the next handler or reject it.