Chain of responsibility design pattern example

๐Ÿ“ฆ Chain of Responsibility Pattern in Java — Step-by-Step Guide

The Chain of Responsibility (CoR) is a behavioral design pattern that allows a request to pass through a chain of handlers.
Each handler decides either to process the request or pass it to the next handler in the chain.

This pattern helps in decoupling senders and receivers — the sender doesn’t need to know which handler will eventually process the request.


๐Ÿง  Concept

  • A chain is a series of objects (handlers) connected together.

  • Each handler knows only about the next handler in the chain.

  • When a request comes in:

    • The current handler checks if it can handle it.

    • If yes → it processes it.

    • If not → it forwards it to the next handler in the chain.


๐Ÿšš Real-World Analogy — Parcel Delivery Service

Imagine a parcel service with branches in:

Bangalore → Bombay → Delhi

When a parcel is sent:

  • A Bangalore branch first receives it.

  • If the parcel is for Bombay, Bangalore forwards it to Bombay.

  • If it’s for Delhi, it goes from Bangalore → Bombay → Delhi.

Each branch only handles parcels for its location, and passes others onward.
That’s exactly how the Chain of Responsibility Pattern works!


⚙️ Implementation — Step by Step


๐Ÿงฉ Step 1: Create the Chain Interface

This defines the contract for all handlers.

package com.vinod.design.chain; public interface Chain { // Sets the next handler in the chain void setNextDestination(Chain nextDestination); // Processes the incoming parcel void processParcel(Parcel parcel); }

๐Ÿงฉ Step 2: Create Handler — Bangalore

package com.vinod.design.chain; public class Bangalore implements Chain { private Chain nextDestination; @Override public void setNextDestination(Chain nextDest) { this.nextDestination = nextDest; } @Override public void processParcel(Parcel parcel) { if (parcel.getDestination().equalsIgnoreCase("Bangalore")) { System.out.println("Processing parcel in Bangalore: " + parcel); } else { // Forward to next branch if not for Bangalore if (nextDestination != null) { nextDestination.processParcel(parcel); } } } }

๐Ÿงฉ Step 3: Create Handler — Bombay

package com.vinod.design.chain; public class Bombay implements Chain { private Chain nextDestination; @Override public void setNextDestination(Chain nextDest) { this.nextDestination = nextDest; } @Override public void processParcel(Parcel parcel) { if (parcel.getDestination().equalsIgnoreCase("Bombay")) { System.out.println("Processing parcel in Bombay: " + parcel); } else if (nextDestination != null) { nextDestination.processParcel(parcel); } } }

๐Ÿงฉ Step 4: Create Handler — Delhi

package com.vinod.design.chain; public class Delhi implements Chain { private Chain nextDestination; @Override public void setNextDestination(Chain nextDest) { this.nextDestination = nextDest; } @Override public void processParcel(Parcel parcel) { if (parcel.getDestination().equalsIgnoreCase("Delhi")) { System.out.println("Processing parcel in Delhi: " + parcel); } else { System.out.println("No branch found for destination: " + parcel.getDestination()); } } }

๐Ÿงฉ Step 5: Create the Parcel Class

package com.vinod.design.chain; public class Parcel { private String source; private String destination; private String details; public String getSource() { return source; } public void setSource(String source) { this.source = source; } public String getDestination() { return destination; } public void setDestination(String destination) { this.destination = destination; } public String getDetails() { return details; } public void setDetails(String details) { this.details = details; } @Override public String toString() { return "Parcel [source=" + source + ", destination=" + destination + ", details=" + details + "]"; } }

๐Ÿงฉ Step 6: Set Up the Chain (Main Class)

package com.vinod.design.chain; public class ParcelService { public static void main(String[] args) { // Create handler objects Chain bangalore = new Bangalore(); Chain bombay = new Bombay(); Chain delhi = new Delhi(); // Build the chain: Bangalore → Bombay → Delhi bangalore.setNextDestination(bombay); bombay.setNextDestination(delhi); // Create test parcels Parcel parcel1 = new Parcel(); parcel1.setDestination("Bombay"); parcel1.setDetails("Parcel to Bombay"); Parcel parcel2 = new Parcel(); parcel2.setDestination("Delhi"); parcel2.setDetails("Parcel to Delhi"); // Send parcels through the chain bangalore.processParcel(parcel1); bangalore.processParcel(parcel2); } }

๐Ÿงพ Output

Processing parcel in Bombay: Parcel [source=null, destination=Bombay, details=Parcel to Bombay] Processing parcel in Delhi: Parcel [source=null, destination=Delhi, details=Parcel to Delhi]

๐Ÿง  How It Works (Step-by-Step Flow)

StepActionExplanation
1️⃣ParcelService sets up the chainBangalore → Bombay → Delhi
2️⃣A request (parcel) starts at BangaloreBangalore checks if destination matches
3️⃣If not, forwards to next handlerThe parcel moves along the chain
4️⃣Handler matches parcel destinationProcesses it and stops the chain
5️⃣If no handler matchesRequest is ignored or logged

๐Ÿ” Benefits of Chain of Responsibility

  • Loose coupling — Sender doesn’t need to know which handler will process the request

  • Extensibility — Add new handlers easily without changing existing code

  • Flexible processing — Handlers can process partially or pass along

  • Separation of concerns — Each handler focuses on one specific job


⚠️ Things to Watch Out For

  • ๐Ÿšซ The chain must be properly linked (missing setNextDestination() can break flow).

  • ⚙️ Handlers should ideally stop propagation once a request is processed.

  • ๐Ÿงฉ Avoid creating circular chains — can cause infinite loops.


๐Ÿงฉ UML-Like Text Diagram

+-------------+ +------------+ +-----------+ Request --> | Bangalore | --> | Bombay | --> | Delhi | +-------------+ +------------+ +-----------+ | | | | | | [Can process?] [Can process?] [Can process?] | | | v v v [Yes → Handle] [Yes → Handle] [Yes → Handle] | | | +------ No ---------+------ No ---------+

๐Ÿ’ฌ Real-World Applications

Use CaseExample
Web request filteringServlet Filters in Java EE (FilterChain)
Logging frameworkDifferent log handlers (Console, File, DB)
Event handling systemsUI event bubbling or middleware
Authorization pipelinesRequest passes through validators or access checkers

No comments:

Post a Comment

Model Context Protocol (MCP) — Complete Guide for Backend Engineers

  Model Context Protocol (MCP) — Complete Guide for Backend Engineers Build Tools, Resources, and AI-Driven Services Using LangChain Moder...

Featured Posts