The refactored code uses the Chain of Responsibility Design Pattern. A request passes through a line of separate handler objects until one of them processes it. This removes the rigid branching, and the sender no longer depends on the receivers.
1. How This Approach Solves the Issues
We replace the one big routing method with a chain of independent handler classes. Each class extends the same base class, so they can be used interchangeably (polymorphism). The code is split into small parts and is easy to extend.
Issue
Solution with Chain of Responsibility
Violation of Open-Closed Principle
To add a handler (e.g., FraudSupport or EscalationSupport), create a new class that extends SupportHandler and link it into the chain. The existing handler classes stay unchanged.
Monolithic Code
Each handler class holds only its own logic. This follows the Single Responsibility Principle (SRP): one class, one job.
Scalability and Flexibility Bottlenecks
You can change the order while the program runs by changing how handlers are linked with setNextHandler(). This lets you build custom routes.
2. Key Components in the Solution
Handler (SupportHandler): An abstract base class. It holds a reference to the next handler (nextHandler) and declares the handleRequest() method that every handler must have.
Concrete Handlers (GeneralSupport, BillingSupport, etc.): Separate classes that check whether the incoming request type is theirs. If it is, they handle it. If not, they pass it to nextHandler.
Client (Main): Builds the chain and sends requests to the first handler. It does not need to know which handler will finally process them.
3. When to Use the Chain of Responsibility Pattern
Multiple Candidate Handlers: When more than one object could process a request, and you cannot tell which one when you write the code.
Dynamic Pipeline Configuration: When you need to arrange, reorder or change the handlers while the program runs.
Decoupling Sender and Receivers: When you want to send a request to several possible receivers without tying the sender to specific receiver classes.
Elimination of Monolithic Conditionals: When one dispatcher method has large if-else or switch blocks that decide which part of the system does the work.
4. Summary of the Architectural Flow
Think of a phone menu at a support center. You dial in, and your call first goes to the General Inquiries desk. If it is a billing question, they transfer you to Billing. If Billing cannot solve it, they pass you to Technical Support. You dial one number, and the company forwards the call inside until the right department answers.
1package DesignPatterns.BehaviouralPatterns.ChainOfResponsibilityPattern.After;2import java.util.*;34// ============================================================================5// 1. ABSTRACT BASE HANDLER6// ============================================================================7/**8 * Defines the unified contract for all links in the processing pipeline.9 * Holds a reference to the next handler in the sequence and provides a 10 * mechanism to build the chain dynamically.11 */12abstract class SupportHandler {13 // Reference pointer to the next processing unit in the chain14 protected SupportHandler nextHandler;1516 /**17 * Builds or mutates the chain link at runtime.18 * Allows dynamic reordering or insertion of handlers without class rewrites.19 */20 public void setNextHandler(SupportHandler nextHandler) {21 this.nextHandler = nextHandler;22 }2324 /**25 * Abstract method encapsulating the handling contract.26 * Subclasses either consume the request or pass it along via nextHandler.27 */28 public abstract void handleRequest(String requestType);29}3031// ============================================================================32// 2. CONCRETE HANDLERS33// ============================================================================34/**35 * Concrete handler for basic/general inquiries.36 * If the request does not match its domain, it forwards the request forward.37 */38class GeneralSupport extends SupportHandler {39 @Override40 public void handleRequest(String requestType) {41 if (requestType.equalsIgnoreCase("general")) {42 System.out.println("GeneralSupport: Handling general query");43 } else if (nextHandler != null) {44 // Forward the request to the next link in the chain45 nextHandler.handleRequest(requestType);46 }47 }48}4950/**51 * Concrete handler for refund and billing-related requests.52 */53class BillingSupport extends SupportHandler {54 @Override55 public void handleRequest(String requestType) {56 if (requestType.equalsIgnoreCase("refund")) {57 System.out.println("BillingSupport: Handling refund request");58 } else if (nextHandler != null) {59 // Pass along if not responsible for this request type60 nextHandler.handleRequest(requestType);61 }62 }63}6465/**66 * Concrete handler for technical bugs and system troubleshooting.67 */68class TechnicalSupport extends SupportHandler {69 @Override70 public void handleRequest(String requestType) {71 if (requestType.equalsIgnoreCase("technical")) {72 System.out.println("TechnicalSupport: Handling technical issue");73 } else if (nextHandler != null) {74 // Pass down the chain75 nextHandler.handleRequest(requestType);76 }77 }78}7980/**81 * Concrete handler for shipping and delivery queries.82 * Acts as the final link in this configuration, handling unhandled fallbacks.83 */84class DeliverySupport extends SupportHandler {85 @Override86 public void handleRequest(String requestType) {87 if (requestType.equalsIgnoreCase("delivery")) {88 System.out.println("DeliverySupport: Handling delivery issue");89 } else if (nextHandler != null) {90 nextHandler.handleRequest(requestType);91 } else {92 // Terminal fallback when no link in the chain can process the request93 System.out.println("DeliverySupport: No handler found for request: " + requestType);94 }95 }96}9798// ============================================================================99// 3. CLIENT CODE & CHAIN CONFIGURATION100// ============================================================================101public class Main {102 public static void main(String[] args) {103 // Step 1: Instantiate individual concrete handlers independently104 SupportHandler general = new GeneralSupport();105 SupportHandler billing = new BillingSupport();106 SupportHandler technical = new TechnicalSupport();107 SupportHandler delivery = new DeliverySupport();108109 // Step 2: Assemble the execution pipeline dynamically110 // General -> Billing -> Technical -> Delivery111 general.setNextHandler(billing);112 billing.setNextHandler(technical);113 technical.setNextHandler(delivery);114115 // Step 3: Trigger requests starting from the head of the chain116 System.out.println("--- Request 1: refund ---");117 general.handleRequest("refund");118119 System.out.println("\n--- Request 2: delivery ---");120 general.handleRequest("delivery");121122 System.out.println("\n--- Request 3: unknown ---");123 general.handleRequest("unknown");124 }125}