Behavioral PatternsChain of ResponsibilityMedium⏱️ ~3 min

Chain of Responsibility: Structure and Participants

Core Structure

The Chain of Responsibility pattern consists of three primary participants that work together to create a flexible request processing pipeline.

«interface»
Handler
+ setNext(handler: Handler): Handler
+ handle(request: Request): void
ConcreteHandlerA
- nextHandler: Handler
+ handle(request: Request): void
- canHandle(request: Request): bool
ConcreteHandlerB
- nextHandler: Handler
+ handle(request: Request): void
- canHandle(request: Request): bool
Client
+ buildChain(): void
+ sendRequest(req: Request): void

Participant Roles

Handler Interface: Defines the contract for all handlers in the chain. It declares the handle() method for processing requests and the setNext() method for linking handlers together. The interface ensures that all concrete handlers follow the same protocol, making them interchangeable.

Concrete Handlers: Implement the Handler interface and contain the actual processing logic. Each concrete handler maintains a reference to the next handler in the chain. When a request arrives, the handler first checks if it can process the request using its canHandle() logic. If yes, it processes the request and optionally stops propagation. If no, it forwards the request to the next handler using nextHandler.handle(request). If no next handler exists, the request remains unhandled.

Client: Builds the chain by creating handler instances and linking them using setNext(). The client then initiates request processing by calling handle() on the first handler. The client does not need to know which handler will ultimately process the request, only that the chain will handle it appropriately.

Request Flow Pattern

Client → HandlerA.handle()
  → if canHandle: process and optionally stop
  → else: HandlerB.handle()
    → if canHandle: process and optionally stop
    → else: HandlerC.handle()
      → until handled or chain ends
Interview Tip: Emphasize that handlers should maintain only a reference to the next handler, not the entire chain. This preserves loose coupling. Also mention that setNext() typically returns Handler to enable fluent chain building: handlerA.setNext(handlerB).setNext(handlerC).

Two Processing Variants

Single Handler Processing: Once a handler processes the request, propagation stops. This is common in authentication or validation chains where only one handler should take action.

Multiple Handler Processing: All applicable handlers process the request sequentially. This is common in logging or middleware pipelines where each handler performs a specific action and then passes the request forward. In this variant, handlers call nextHandler.handle() after their own processing, not instead of it.

💡 Key Takeaways
Handler interface defines common contract with handle() and setNext() methods
Concrete handlers maintain reference only to next handler, preserving loose coupling
Client builds chain by linking handlers and initiates processing through first handler
Request flows through chain until a handler processes it or chain ends
Two variants exist: single handler processing (stop on first match) or multiple handler processing (all applicable handlers act)
📌 Examples
1Authentication chain: Token validator passes to Session validator passes to Basic auth
2Logging pipeline: Request logger passes to Security logger passes to Performance logger
3Validation chain: Null check passes to Format validator passes to Business rule validator
← Back to Chain of Responsibility Overview
Chain of Responsibility: Structure and Participants | Chain of Responsibility - System Overflow