Chain of Responsibility Pattern in Java? Example Tutorial

Hello guys, if you have been doing Java development then you must have come across design pattern, tried and tested solution of common software problem. In the past, we have looked at several popular Object Oriented Design Patterns in Java like Adapter, Decorator, State, Strategy, Template, Composite, Command, Observer, Factory, Builder, Visitor etc, and today I am going to talk about Chain of Responsibility design pattern in Java. The Chained or Chain of Responsibility Pattern is a design pattern that allows a request to be passed along a chain of objects until it is handled by one of the objects in the chain. This pattern is helpful for situations where it is not known in advance which object in the chain should handle the request, or where the request needs to be handled by multiple objects in the chain.

Chained Or Chain Of Responsibility Pattern with Examples

In the Chained or Chain of Responsibility Pattern, each object in the chain has the opportunity to handle the request, and if it is unable to do so, it passes the request along to the next object in the chain. This allows for a flexible and dynamic approach to request handling, as the chain can be modified at runtime to add or remove objects as needed.

In Java, the Chained or Chain of Responsibility Pattern can be implemented using inheritance or composition.

1. Chain of Responsibility Pattern using Inheritance in Java

One way to implement the Chained or Chain of Responsibility Pattern in Java is by using inheritance. In this approach, a base class or interface defines the methods for handling a request and for setting the next object in the chain. 

Concrete subclasses or implementations of the base class or interface then implement the request handling logic and can override the method for setting the next object in the chain to specify the next object in the chain for their particular case.

Here is an example of the Chained or Chain of Responsibility Pattern using inheritance in Java:

public interface RequestHandler {
    void handleRequest(Request request);
    void setNext(RequestHandler next);
}

public class ConcreteRequestHandler1 implements RequestHandler {
    private RequestHandler next;

    @Override
    public void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE1) {
            // handle request
        } else {
            next.handleRequest(request);
        }
    }

    @Override
    public void setNext(RequestHandler next) {
        this.next = next;
    }
}

public class ConcreteRequestHandler2 implements RequestHandler {
    private RequestHandler next;

    @Override
    public void handleRequest(Request request) {
        if (request.getType() == RequestType.TYPE2) {
            // handle request
        } else {
            next.handleRequest(request);
        }
    }

    @Override
    public void setNext(RequestHandler next) {
        this.next = next;
    }
}

// ...

RequestHandler handler1 = new ConcreteRequestHandler1();
RequestHandler handler2 = new ConcreteRequestHandler2();
handler1.setNext(handler2);
handler1.handleRequest(new Request(RequestType.TYPE1));
handler1.handleRequest(new Request(RequestType.TYPE2));

In this example, the RequestHandler interface defines the methods for handling a request and setting the next object in the chain. The ConcreteRequestHandler1 and ConcreteRequestHandler2 classes implement the RequestHandler interface and provide the request handling logic for their respective request types. 

The objects in the chain are created and linked together using the setNext() method, and the request is passed along the chain using the handleRequest() method.





2. Chain of Responsibility Pattern using Composition in Java

Another way to implement the Chained or Chain of Responsibility Pattern in Java is by using composition. In this approach, each object in the chain has a reference to the next object in the chain and implements the request handling logic directly. 

This approach allows for more flexibility and reuse, as the objects in the chain can be composed at runtime and can be shared among multiple chains.

Here is an example of the Chained or Chain of Responsibility Pattern using composition in Java:

ublic class RequestHandler {
    private RequestHandler next;

    public void handleRequest(Request request) {
        if (canHandleRequest(request)) {
            // handle request
        } else if (next != null) {
            next.handleRequest(request);
        }
    }

    public void setNext(RequestHandler next) {
        this.next = next;
    }

    protected boolean canHandleRequest(Request request) {
        // implementation specific logic for determining if the request can be handled
        return false;
    }
}

public class ConcreteRequestHandler1 extends RequestHandler {
    @Override
    protected boolean canHandleRequest(Request request) {
        return request.getType() == RequestType.TYPE1;
    }
}

public class ConcreteRequestHandler2 extends RequestHandler {
    @Override
    protected boolean canHandleRequest(Request request) {
        return request.getType() == RequestType.TYPE2;
    }
}

// ...

RequestHandler handler1 = new ConcreteRequestHandler1();
RequestHandler handler2 = new ConcreteRequestHandler2();
handler1.setNext(handler2);
handler1.handleRequest(new Request(RequestType.TYPE1));
handler1.handleRequest(new Request(RequestType.TYPE2));

In this example, the RequestHandler class defines the basic structure of an object in the chain and provides the logic for passing the request along the chain. The ConcreteRequestHandler1 and ConcreteRequestHandler2 classes extend the RequestHandler class and override the canHandleRequest() method to provide the request handling logic for their respective request types.

The objects in the chain are created and linked together using the setNext() method, and the request is passed along the chain using the handleRequest() method.




3. Advantages and Disadvantages

The Chained or Chain of Responsibility Pattern has several advantages and disadvantages that should be considered when deciding whether to use it in a project.

Advantages:
  • Decoupling: The Chained or Chain of Responsibility Pattern decouples the sender of a request from its receiver, allowing the objects in the chain to be changed or modified independently.
  • Flexibility: The Chained or Chain of Responsibility Pattern allows for a flexible and dynamic approach to request handling, as the chain can be modified at runtime to add or remove objects as needed.
  • Reuse: The Chained or Chain of Responsibility Pattern allows for the reuse of objects in the chain, as they can be shared among multiple chains.
Disadvantages:
  • Complexity: The Chained or Chain of Responsibility Pattern can introduce additional complexity to the system, as it requires the creation and management of multiple objects in the chain.
  • Performance: The Chained or Chain of Responsibility Pattern can have a negative impact on performance, as each object in the chain has to process the request, even if it is not the final handler.
  • Debugging: The Chained or Chain of Responsibility Pattern can make it more difficult to debug the system, as it is not always clear which object in the chain is responsible for handling a particular request.




Conclusion

That's all about Chain of Responsibility pattern in Java. The Chained or Chain of Responsibility Pattern is a design pattern that allows a request to be passed along a chain of objects until it is handled by one of the objects in the chain. This pattern is useful for situations where it is not known in advance which object in the chain should handle the request, or where the request needs to be handled by multiple objects in the chain. 

In Java, the Chained or Chain of Responsibility Pattern can be implemented using inheritance or composition. Inheritance allows for a simple and straightforward implementation, but it has limited flexibility and reuse. Composition allows for more flexibility and reuse, but it requires more complex code to manage the objects in the chain.

Other Java Design Patterns tutorials you may like
  • How to design a Vending Machine in Java? (questions)
  • How to implement a Decorator design pattern in Java? (tutorial)
  • 5 Free Courses to learn Object Oriented Programming (courses)
  • 7 Best Courses to learn Design Pattern in Java (courses)
  • How to implement the Strategy Design Pattern in Java? (example)
  • 10 OOP Design Principle Every Java developer should learn (solid principle)
  • 30 System Design Problems for interviews (System design problems)
  • How to create thread-safe Singleton in Java (example)
  • 7 Best Books to learn the Design Pattern in Java? (books)
  • Difference between Factory and Dependency Injection Pattern? (answer)
  • 20 Software Design and Design Pattern Interview questions (design questions)
  • Difference between State and Strategy Design Pattern in Java? (answer)
  • 18 Java Design Pattern Interview Questions with Answers (list)
  • 20 System Design Interview Questions (list)
  • 5 Free Courses to learn Data Structure and Algorithms (courses)
  • 7 Books to learn System Design for Beginners (System design books)
  • Difference between Factory and Abstract Factory Pattern? (example)

Thanks a lot for reading this article so far. If you like this explanation and implementation of Chain of Responsibility Pattern in Java  then please share it with your friends and colleagues. If you have any questions or feedback then please drop a note.

P. S. - If you are an experienced Java developer and want to learn Design patterns and looking for a best design pattern resources like books and online courses then you can also check out this list of best design pattern courses for experience developers to start with. It contains online courses to learn design pattern and how to use them in real world coding.

No comments:

Post a Comment

Feel free to comment, ask questions if you have any doubt.