One of the common design patterns -- responsibility chain pattern

Posted by miles_rich on Fri, 10 Dec 2021 12:29:18 +0100

preface

In real life, it is a common scene that an event needs to be processed by multiple objects. For example, purchase approval process, leave process, etc. When the company's employees ask for leave, the leaders who can approve the leave include department heads, deputy general managers, general managers, etc., but the number of days each leader can approve is different. Employees must find different leaders to sign according to the number of days they need to ask for leave, that is to say, employees must remember the name, telephone number, address and other information of each leader, which undoubtedly increases the difficulty.

There are also related examples in computer software and hardware, such as datagram transmission in bus network. Each computer determines whether to receive according to whether the target address is the same as its own address; In addition, in exception handling, the handler decides whether to handle the exception according to the type of exception; There are also struts 2 interceptors, JSP and Servlet filters, all of which can be implemented using the responsibility chain model.

Definition and characteristics of pattern

Definition of Chain of Responsibility mode: in order to avoid coupling the request sender with multiple request handlers, all request handlers are connected into a chain by remembering the reference of the next object through the previous object; When a request occurs, it can be passed along the chain until an object processes it.

In the responsibility chain mode, the customer only needs to send the request to the responsibility chain, and does not need to care about the processing details of the request and the transmission process of the request. The request will be transmitted automatically. Therefore, the responsibility chain decouples the sender of the request from the handler of the request.

  1. Reduces the coupling between objects. This mode makes an object do not need to know which object handles its request and the structure of the chain, and the sender and receiver do not need to have each other's clear information.
  2. It enhances the scalability of the system. New request processing classes can be added as needed to meet the opening and closing principle.
  3. Increased flexibility in assigning responsibilities to objects. When the workflow changes, you can dynamically change the members in the chain or transfer their order, or dynamically add or delete responsibilities.
  4. The chain of responsibility simplifies the connection between objects. Each object only needs to maintain a reference to its successor without maintaining the references of all other processors, which avoids the use of many if or if ·· else statements.
  5. Responsibility sharing. Each class only needs to deal with its own work that should be handled, and the work that should not be handled should be transferred to the next object for completion. The scope of responsibility of each class should be defined and in line with the principle of single responsibility of the class.

Its main disadvantages are as follows.

  1. There is no guarantee that every request will be processed. Since a request has no specific receiver, it cannot be guaranteed that it will be processed. The request may not be processed until it reaches the end of the chain.
  2. For a long responsibility chain, the processing of requests may involve multiple processing objects, and the system performance will be affected to some extent.
  3. The rationality of the establishment of responsibility chain depends on the client, which increases the complexity of the client, and may lead to system errors due to the wrong setting of responsibility chain, such as circular call.

Structure and implementation of pattern

Usually, the data structure of responsibility chain mode can be realized through data link list

Pattern structure

The responsibility chain model mainly includes the following roles.

  1. Abstract Handler role: define an interface for processing requests, including abstract processing methods and a subsequent connection.
  2. Concrete Handler role: implement the processing method of the abstract handler to judge whether the request can be processed. If the request can be processed, process it. Otherwise, transfer the request to its successor.
  3. Client role: create a processing chain and submit a request to the specific handler object of the chain head. It does not care about the processing details and the transmission process of the request.

The essence of responsibility chain mode is to decouple request and processing, so that requests can be transmitted and processed in the processing chain; Understanding the responsibility chain model should understand its model, not its specific implementation. The unique feature of the responsibility chain model is that it combines its node processors into a chain structure, and allows the node to decide whether to process or forward the request, which is equivalent to making the request flow.

Implementation of pattern

The implementation code of responsibility chain mode is as follows:

public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        //Assembly responsibility chain
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setNext(handler2);
        //Submit request
        handler1.handleRequest("two");
    }
}
//Abstract handler role
abstract class Handler {
    private Handler next;
    public void setNext(Handler next) {
        this.next = next;
    }
    public Handler getNext() {
        return next;
    }
    //Method of processing request
    public abstract void handleRequest(String request);
}
//Specific processor role 1
class ConcreteHandler1 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("one")) {
            System.out.println("Specific handler 1 is responsible for processing the request!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("No one is processing the request!");
            }
        }
    }
}
//Specific processor role 2
class ConcreteHandler2 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("two")) {
            System.out.println("Specific handler 2 is responsible for processing the request!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("No one is processing the request!");
            }
        }
    }
}
/*
The running results of the program are as follows:
Specific handler 2 is responsible for processing the request!
*/

/*    
In the above code, we hard code the message as String type, but in real business, the message is diverse, which can be int, String or user-defined type. Therefore, based on the above code, the message type can be abstracted Request, which enhances the compatibility of messages.*/

Topics: Java Design Pattern server