Fundamentals 7 min read

Chain of Responsibility Pattern: Elegantly Handle Multi-Level Requests in Java

This article explains the Chain of Responsibility design pattern with a practical Java example of a leave approval workflow, showing how it decouples request senders from receivers and enables flexible, extensible handling through a chain of handlers.

Full-Stack Internet Architecture
Full-Stack Internet Architecture
Full-Stack Internet Architecture
Chain of Responsibility Pattern: Elegantly Handle Multi-Level Requests in Java

Introduction

The article opens with a real-world scenario: looking up an IP location by trying multiple external services (Taobao, Baidu, etc.) sequentially until one succeeds. This motivates the need for a pattern that handles requests through a chain of processors, improving extensibility and maintainability.

Pattern Definition

The Chain of Responsibility pattern allows multiple objects to handle a request, avoiding coupling between sender and receiver. Receivers are linked in a chain; the request passes along until an object handles it.

Chain of Responsibility definition diagram
Chain of Responsibility definition diagram

Core Roles

Abstract Handler (Handler) : Defines the common request handling interface and a reference to the next handler.

Concrete Handler (Concrete Handler) : Implements the handling logic; if it cannot handle the request, it forwards to the next handler.

Client (Client) : Builds the chain and initiates the request without knowing the concrete handlers or chain length.

UML Class Diagram

Chain of Responsibility UML class diagram
Chain of Responsibility UML class diagram

Java Implementation: Leave Approval Example

The article demonstrates the pattern with a company leave approval workflow:

≤3 days: Team Leader approves.

3–5 days: Manager approves.

>5 days: Director approves.

Request Class

package com.sample.patterns.cor;

// Request class
public class Request {
    // Leave days
    private Integer days;
    private Integer requestId;

    public Request(Integer days, Integer requestId) {
        this.days = days;
        this.requestId = requestId;
    }

    public Integer getDays() {
        return days;
    }

    public void setDays(Integer days) {
        this.days = days;
    }

    public Integer getRequestId() {
        return requestId;
    }

    public void setRequestId(Integer requestId) {
        this.requestId = requestId;
    }
}

Abstract Handler

package com.sample.patterns.cor;

// Abstract Handler
public abstract class Handler {
    // Next handler
    private Handler successor;

    public void setSuccessor(Handler successor) {
        this.successor = successor;
    }

    public Handler getSuccessor() {
        return this.successor;
    }

    public abstract void handleRequest(Request request);
}

Concrete Handlers

LeaderHandler (Team Leader): handles requests ≤3 days.

package com.sample.patterns.cor;

// Team Leader handler
public class LeaderHandler extends Handler {
    @Override
    public void handleRequest(Request request) {
        if (request.getDays() <= 3) {
            System.out.println("Team Leader approves!");
        } else {
            getSuccessor().handleRequest(request);
        }
    }
}

ManagerHandler (Manager): handles requests >3 and ≤5 days.

package com.sample.patterns.cor;

// Manager handler
public class ManagerHandler extends Handler {
    @Override
    public void handleRequest(Request request) {
        if (request.getDays() > 3 && request.getDays() <= 5) {
            System.out.println("Manager approves!");
        } else {
            getSuccessor().handleRequest(request);
        }
    }
}

DirectorHandler (Director): handles requests >5 days.

package com.sample.patterns.cor;

// Director handler
public class DirectorHandler extends Handler {
    @Override
    public void handleRequest(Request request) {
        if (request.getDays() > 5) {
            System.out.println("Director approves!");
        } else {
            getSuccessor().handleRequest(request);
        }
    }
}

Client: Building and Testing the Chain

package com.sample.patterns.cor;

public class Client {
    public static void main(String[] args) {
        Handler leader = new LeaderHandler();
        Handler manager = new ManagerHandler();
        Handler director = new DirectorHandler();

        leader.setSuccessor(manager);
        manager.setSuccessor(director);

        Request request1 = new Request(4, 1);
        leader.handleRequest(request1);
        Request request2 = new Request(10, 2);
        leader.handleRequest(request2);
    }
}

Execution Results and Extensibility

Testing shows:

4-day request: LeaderHandler cannot handle (exceeds 3 days), passes to ManagerHandler which approves.

10-day request: Passes through LeaderHandler and ManagerHandler, finally approved by DirectorHandler.

Adding a new approval level (e.g., General Manager) only requires creating a new GeneralManagerHandler and linking it after DirectorHandler, without modifying existing handler code (though DirectorHandler's threshold may need adjustment). This demonstrates the pattern's decoupling and extensibility.

Conclusion

The Chain of Responsibility pattern decouples request senders from receivers, enhancing code flexibility and extensibility while keeping the structure elegant.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

Chain of Responsibilitydesign patternsJavaUMLExtensibilityDecouplingBehavioral PatternsLeave Approval
Full-Stack Internet Architecture
Written by

Full-Stack Internet Architecture

Introducing full-stack Internet architecture technologies centered on Java

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.