Christopher Anabo
Christopher Anabo
Senior Tech Lead
Christopher Anabo

Notes

Chain of Responsibility Design Pattern

Chain of Responsibility Design Pattern

The Chain of Responsibility design pattern is a behavioral design pattern that allows an object to pass a request along a chain of handlers. Each handler in the chain decides either to process the request or to pass it along the chain to the next handler.

 

What is the Chain of Responsibility Design Pattern?

Chain of Responsibility Pattern or Chain of Responsibility Method is a Behavioral Design Pattern, which allows an object to send a request to other objects without knowing who is going to handle it.

  • This pattern is frequently used in the chain of multiple objects, where each object either handles the request or passes it on to the next object in the chain if it is unable to handle that request.
  • This pattern encourages loose coupling between sender and receiver, providing freedom in handling the request.

 

Characteristics of the Chain of Responsibility Design Pattern

Below are the main characteristics of chain of responsibility design pattern:

  • Loose Coupling: This means the sender of a request doesn’t need to know which specific object will handle it. Similarly, the handler doesn’t need to understand how the requests are sent. This keeps the components separate and flexible.
  • Dynamic Chain: While the program is running, changing the chain is simple. This makes your code incredibly flexible because you may add or delete handlers without changing the main body of the code.
  • Single Responsibility Principle: Each handler in the chain has one job: either to handle the request or to pass it to the next handler. This keeps the code organized and focused, making it easier to manage.
  • Sequential Order: Requests move through the chain one at a time. Each handler gets a chance to process the request in a specific order, ensuring consistency.
  • Fallback Mechanism: If a request isn’t handled by any of the handlers, the chain can include a fallback option. This means there’s a default way to deal with requests that don’t fit anywhere else.

Real-World Analogy of the Chain Of Responsibility Design Pattern

Imagine a customer service department with multiple levels of support staff, each responsible for handling different types of customer inquiries based on their complexity. The chain of responsibility can be illustrated as follows:

Complete code for the above example

Below is the complete code for the above example:

Java

// Handler Interface
interface SupportHandler {
    void handleRequest(Request request);
    void setNextHandler(SupportHandler nextHandler);
}

// Concrete Handlers
class Level1SupportHandler implements SupportHandler {
    private SupportHandler nextHandler;

    public void setNextHandler(SupportHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handleRequest(Request request) {
        if (request.getPriority() == Priority.BASIC) {
            System.out.println("Level 1 Support handled the request.");
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

class Level2SupportHandler implements SupportHandler {
    private SupportHandler nextHandler;

    public void setNextHandler(SupportHandler nextHandler) {
        this.nextHandler = nextHandler;
    }

    public void handleRequest(Request request) {
        if (request.getPriority() == Priority.INTERMEDIATE) {
            System.out.println("Level 2 Support handled the request.");
        } else if (nextHandler != null) {
            nextHandler.handleRequest(request);
        }
    }
}

class Level3SupportHandler implements SupportHandler {
    public void handleRequest(Request request) {
        if (request.getPriority() == Priority.CRITICAL) {
            System.out.println("Level 3 Support handled the request.");
        } else {
            System.out.println("Request cannot be handled.");
        }
    }

    public void setNextHandler(SupportHandler nextHandler) {
        // No next handler for Level 3
    }
}

// Request Class
class Request {
    private Priority priority;

    public Request(Priority priority) {
        this.priority = priority;
    }

    public Priority getPriority() {
        return priority;
    }
}

// Priority Enum
enum Priority {
    BASIC, INTERMEDIATE, CRITICAL
}

// Main Class
public class Main {
    public static void main(String[] args) {
        SupportHandler level1Handler = new Level1SupportHandler();
        SupportHandler level2Handler = new Level2SupportHandler();
        SupportHandler level3Handler = new Level3SupportHandler();

        level1Handler.setNextHandler(level2Handler);
        level2Handler.setNextHandler(level3Handler);

        Request request1 = new Request(Priority.BASIC);
        Request request2 = new Request(Priority.INTERMEDIATE);
        Request request3 = new Request(Priority.CRITICAL);

        level1Handler.handleRequest(request1);
        level1Handler.handleRequest(request2);
        level1Handler.handleRequest(request3);
    }
}

Output

Level 1 Support handled the request.
Level 2 Support handled the request.
Level 3 Support handled the request.