MTI TEK
  • Home
  • About
  • LLMs
  • Docker
  • Kubernetes
  • Java
  • All Resources
Java Design Patterns | Chain of Responsibility
  1. Overview and Definition
  2. Class Diagram
  3. Implementation Example
    • The Request Object
    • The Abstract Handler
    • The Concrete Handlers
    • Testing the Chain of Responsibility Pattern

  1. Overview and Definition
    The Chain of Responsibility pattern is a behavioral design pattern that passes requests along a chain of handlers. Upon receiving a request, each handler decides either to process the request or to pass it to the next handler in the chain. This pattern allows multiple objects to handle a request without coupling the sender to specific receivers.

    Key Components:
    • Handler: Defines an interface for handling requests and optionally implements the successor link.
    • Concrete Handler: Handles requests it is responsible for and can access its successor to pass unhandled requests.
    • Request: Contains the data and context needed for processing by the handlers.
    • Client: Initiates the request to a Concrete Handler object on the chain.

    Benefits:
    • Decoupling: Reduces coupling between sender and receiver by giving multiple objects a chance to handle the request.
    • Flexibility: Allows adding or removing responsibilities dynamically by changing the chain members or their order.
    • Single Responsibility: Each handler focuses on a specific type of processing logic.
  2. Class Diagram
    Chain of Responsibility Pattern Components:
    • Handler: Handler abstract class - defines the interface for handling requests and managing the chain.
    • Concrete Handlers: FirstLevelHandler, SecondLevelHandler, ThirdLevelHandler classes - handle specific types of requests.
    • Request: SupportRequest class - contains the request data and severity level.
    ┌────────────────────────────────────────┐
    │              <<abstract>>              │
    │                Handler                 │  ← Abstract Handler
    ├────────────────────────────────────────┤
    │ - nextHandler: Handler                 │
    │ + setNextHandler(Handler): void        │
    │ + handleRequest(SupportRequest): void  │
    │ # canHandle(SupportRequest): boolean   │
    │ # processRequest(SupportRequest): void │
    └────────────────────────────────────────┘
                  △
                  │ extends
                  │
    ┌────────────────────┬─────────────────────┬───────────────────┐
    │ FirstLevelHandler  │ SecondLevelHandler  │ ThirdLevelHandler │  ← Concrete Handlers
    ├────────────────────┼─────────────────────┼───────────────────┤
    │+ canHandle()       │+ canHandle()        │+ canHandle()      │
    │+ processRequest()  │+ processRequest()   │+ processRequest() │
    └────────────────────┴─────────────────────┴───────────────────┘
    
    
    ┌───────────────────────────────┐
    │        SupportRequest         │  ← Request
    ├───────────────────────────────┤
    │ - message: String             │
    │ - severity: int               │
    │ + SupportRequest(String, int) │
    │ + getMessage(): String        │
    │ + getSeverity(): int          │
    └───────────────────────────────┘
                    
  3. Implementation Example
    • The Request Object:
      The Request object contains the data and context that handlers need to process. It includes information that helps handlers decide whether they can handle the request.
      public class SupportRequest {
          private String message;
          private int severity;
      
          public SupportRequest(String message, int severity) {
              this.message = message;
              this.severity = severity;
          }
      
          public String getMessage() {
              return message;
          }
      
          public int getSeverity() {
              return severity;
          }
      }
    • The Abstract Handler:
      The Abstract Handler defines the interface for handling requests and manages the chain structure. It implements the chain traversal logic and defines abstract methods for concrete handlers to implement.
      public abstract class Handler {
          private Handler nextHandler;
      
          public void setNextHandler(Handler nextHandler) {
              this.nextHandler = nextHandler;
          }
      
          public void handleRequest(SupportRequest request) {
              if (canHandle(request)) {
                  processRequest(request);
              } else if (nextHandler != null) {
                  nextHandler.handleRequest(request);
              } else {
                  System.out.println("No handler available for request: " + request.getMessage());
              }
          }
      
          protected abstract boolean canHandle(SupportRequest request);
          protected abstract void processRequest(SupportRequest request);
      }
    • The Concrete Handlers:
      Concrete Handlers implement the decision logic to determine if they can handle a request. Each handler is responsible for a specific type or level of request processing.

      First Level Handler:
      public class FirstLevelHandler extends Handler {
          @Override
          protected boolean canHandle(SupportRequest request) {
              return request.getSeverity() == 1;
          }
      
          @Override
          protected void processRequest(SupportRequest request) {
              System.out.println("FirstLevelHandler processed: " + request.getMessage());
          }
      }
      Second Level Handler:
      public class SecondLevelHandler extends Handler {
          @Override
          protected boolean canHandle(SupportRequest request) {
              return request.getSeverity() == 2;
          }
      
          @Override
          protected void processRequest(SupportRequest request) {
              System.out.println("SecondLevelHandler processed: " + request.getMessage());
          }
      }
      Third Level Handler:
      public class ThirdLevelHandler extends Handler {
          @Override
          protected boolean canHandle(SupportRequest request) {
              return request.getSeverity() > 2;
          }
      
          @Override
          protected void processRequest(SupportRequest request) {
              System.out.println("ThirdLevelHandler processed: " + request.getMessage());
          }
      }
    • Testing the Chain of Responsibility Pattern:
      The client code demonstrates how requests are passed along the chain until a suitable handler is found. Different requests with varying priorities are routed to appropriate handlers automatically.
      public class ChainOfResponsibilityPatternTest {
          public static void main(String[] args) {
              // Create handlers
              Handler firstLevelHandler = new FirstLevelHandler();
              Handler secondLevelHandler = new SecondLevelHandler();
              Handler thirdLevelHandler = new ThirdLevelHandler();
      
              // Set up the chain
              firstLevelHandler.setNextHandler(secondLevelHandler);
              secondLevelHandler.setNextHandler(thirdLevelHandler);
      
              // Create different requests
              SupportRequest request1 = new SupportRequest("Password reset issue", 1);
              SupportRequest request2 = new SupportRequest("Software installation problem", 2);
              SupportRequest request3 = new SupportRequest("Critical system outage", 3);
      
              System.out.println("Processing Support Requests");
              
              // Process requests through the chain
              firstLevelHandler.handleRequest(request1);
              firstLevelHandler.handleRequest(request2);
              firstLevelHandler.handleRequest(request3);
          }
      }
© 2025 mtitek