Skip to content

Understanding the Chain of Responsibility Design Pattern

Posted on:September 17, 2022 at 01:13 PM

In this blog post, we will explore the Chain of Responsibility design pattern, a behavioral design pattern that allows us to define a sequence of processing components for a request. Each component in the chain can either process the request, modify it, or pass it along to the next component in the chain.

Table of contents

Open Table of contents

Sections

The Need for the Chain Of Responsability Pattern

In software development, we often encounter situations where a change in one part of the system needs to be communicated to other parts. This is especially true in scenarios where multiple components or modules need to stay in sync with the changes occurring in a particular element. The Chain Of Responsability pattern provides an elegant solution to this problem by establishing a subscription mechanism.

Overview of the Chain of Responsibility Pattern

The Chain of Responsibility pattern is all about handling a request through a chain of handler objects. The request is passed from one handler to another along the chain until one of the handlers processes the request or it reaches the end of the chain.

Let’s visualize this with a simple diagram:

ChainOfResponsabilityGraphicProblem

Each handler in the chain holds a reference to the next handler. This allows for flexibility in the handling process. A handler can decide to process the request and terminate the chain, or it can modify the request and pass it to the next handler.

Key Elements of the Pattern

Handler Interface:

This interface defines the method(s) to handle the request.

Concrete Handlers:

Classes that implement the Handler interface. Each concrete handler decides whether to process the request or pass it to the next handler in the chain.

Client:

Initiates the chain and sends the request to the first handler.

Implementing the Chain of Responsibility

Let’s illustrate the pattern with a simple example where we simulate a network request and add headers before sending it out.

Handler Interface

public interface Handler {
    String addHeader(String inputHeader);
}

Concrete Handlers

AuthenticationHandler

public class AuthenticationHandler implements Handler {
    private String authToken;
    private Handler nextHandler;

    public AuthenticationHandler(String authToken) {
        this.authToken = authToken;
    }

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

    @Override
    public String addHeader(String inputHeader) {
        String outputHeader = inputHeader + "\nAuthentication: " + authToken;
        if (nextHandler != null) {
            return nextHandler.addHeader(outputHeader);
        }
        return outputHeader;
    }
}

ContentTypeHandler

public class ContentTypeHandler implements Handler {
    private String contentType;
    private Handler nextHandler;

    public ContentTypeHandler(String contentType) {
        this.contentType = contentType;
    }

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

    @Override
    public String addHeader(String inputHeader) {
        String outputHeader = inputHeader + "\nContent-Type: " + contentType;
        if (nextHandler != null) {
            return nextHandler.addHeader(outputHeader);
        }
        return outputHeader;
    }
}

PayloadHandler

public class PayloadHandler implements Handler {
    private String payload;

    public PayloadHandler(String payload) {
        this.payload = payload;
    }

    @Override
    public String addHeader(String inputHeader) {
        // For simplicity, we don't modify the header in this handler
        return inputHeader;
    }
}

Client Code

public class Client {
    public static void main(String[] args) {
        AuthenticationHandler authHandler = new AuthenticationHandler("12345");
        ContentTypeHandler contentTypeHandler = new ContentTypeHandler("application/json");
        PayloadHandler payloadHandler = new PayloadHandler("{ \"username\": \"John\" }");

        // Construct the chain
        authHandler.setNextHandler(contentTypeHandler);
        contentTypeHandler.setNextHandler(payloadHandler);

        // Send a request through the chain
        String requestHeader = "Request Header:";
        String resultHeader = authHandler.addHeader(requestHeader);

        System.out.println("Result Header:\n" + resultHeader);
    }
}

Conclusion

The Chain of Responsibility design pattern allows for flexible request handling by constructing a chain of handlers. Each handler decides whether to process the request or pass it to the next handler. This pattern promotes decoupling and enables easy extension of the processing logic.

Understanding and effectively implementing the Chain of Responsibility pattern can enhance the modularity and scalability of your software systems, leading to more maintainable and efficient code. Feel free to experiment with the provided example and customize it to suit your specific use cases. Happy coding! 🚀