Design pattern - "responsibility chain pattern"“

Posted by Shamrox on Wed, 29 Dec 2021 17:59:29 +0100

Responsibility chain model

From the perspective of words, we can first focus on the word "chain", which is easy to associate with the chain structure. For example, the drum and flower passing game is a typical chain structure. Everyone forms a chain and transmits to each other. From another perspective, the responsibility chain is the so-called multi-level structure. For example, when you go to the hospital to issue a sick leave note, the general doctor can only issue a one-day certificate. If you need more time, you need to transfer the issuing responsibility to the superior. The superior doctor can only issue a three-day certificate. If you need more time, you need to transfer the responsibility to his superior, and so on, This is a typical application of the responsibility chain model. Another example is the company asking for leave. According to the different times of asking for leave, the levels to be submitted are also different. This hierarchical relationship is a multi-level structure.

What is the responsibility chain model

In the Chain Of Responsibility mode, multiple objects have the opportunity to process the request, so as to avoid the coupling relationship between the sender and receiver of the request. Connect the object into a chain and pass the request along the chain until an object processes it.

Usage scenario

  • There are multiple objects that can handle the same request.
  • Submit requests to multiple objects without explicitly specifying the recipient
  • You can dynamically specify a set of objects to handle requests

Structure and implementation of pattern

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

  1. UML structure diagram is as follows:

2. Implementation code

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!");
            }
        }
    }
}

Among them, Handler is an abstract Handler, which defines an interface to process requests; ConcreteHandler is a specific Handler. It handles the request it is responsible for and can access its successor. If it can handle the request, it will handle it. Otherwise, it will forward the request to its successor.

case

OA system purchase approval requirements

Purchase approval items of school OA system: the requirements are
1) Purchaser purchases teaching equipment
2) If the amount is less than or equal to 5000, it shall be approved by the teaching Director (0 < x < = 5000)
3) If the amount is less than or equal to 10000, it shall be approved by the president (5000 < x < = 10000)
4) If the amount is less than or equal to 30000, it shall be approved by the vice president (10000 < x < = 30000)
5) If the amount exceeds 30000, it shall be approved by the president (30000 < x)

Design class diagram:

code implementation

Step 1 (request class):

public class PurchaseRequest {
    private int type;//Request type
    private float price = 0.0f;
    private int id = 0;

    //constructor 
    public PurchaseRequest(int type, float price, int id) {
        this.type = type;
        this.price = price;
        this.id = id;
    }

    public int getType() {
        return type;
    }

    public float getPrice() {
        return price;
    }

    public int getId() {
        return id;
    }
}

Step 2 (abstract processing class):

public abstract class Approver {

    Approver approver;//Next processor
    String name;//name

    public Approver(String name){
        this.name = name;
    }

    //Next processor
    public void setApprover(Approver approver){
        this.approver = approver;
    }

    //The method of processing the approval request obtains a request and the processing subclass is completed. Therefore, the method is made abstract
    public abstract void processRequest(PurchaseRequest purchaseRequest);
}

Step 3 (specific handler class):

//Teaching director
public class DepartmentApprover extends Approver{

    public DepartmentApprover(String name){
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() <= 5000){
            System.out.println("Request number id=" + purchaseRequest.getId() + "cover" + this.name + "handle");
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
}
//dean
public class CollegeApprover extends Approver{
    public CollegeApprover(String name){
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() < 5000 && purchaseRequest.getPrice() <= 10000){
            System.out.println("Request number id=" + purchaseRequest.getId() + "cover" + this.name + "handle");
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
}
//vice-principal
public class ViceSchoolMasterApprover extends  Approver{
    public ViceSchoolMasterApprover(String name){
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() < 10000 && purchaseRequest.getPrice() <= 30000){
            System.out.println("Request number id=" + purchaseRequest.getId() + "cover" + this.name + "handle");
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
}
principal
public class SchoolMasterApprover extends Approver{
    public SchoolMasterApprover(String name){
        super(name);
    }
    @Override
    public void processRequest(PurchaseRequest purchaseRequest) {
        if(purchaseRequest.getPrice() > 30000){
            System.out.println("Request number id=" + purchaseRequest.getId() + "cover" + this.name + "handle");
        }else{
            approver.processRequest(purchaseRequest);
        }
    }
}

Step 4 (client):

public class Client {
    public static void main(String[] args) {
        //Create a request
        PurchaseRequest purchaseRequest = new PurchaseRequest(1, 31000, 1);

        //Create relevant approvers
        DepartmentApprover departmentApprover = new DepartmentApprover("Director Zhang");
        CollegeApprover collegeApprover = new CollegeApprover("President Li");
        ViceSchoolMasterApprover viceSchoolMasterApprover = new ViceSchoolMasterApprover("Vice president Wang");
        SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("Principal Tong");

        //Set the next of each approval level (processing forms a ring)
        departmentApprover.setApprover(collegeApprover);
        collegeApprover.setApprover(viceSchoolMasterApprover);
        viceSchoolMasterApprover.setApprover(schoolMasterApprover);
        schoolMasterApprover.setApprover(departmentApprover);


        departmentApprover.processRequest(purchaseRequest);
    }
}

Precautions and details

  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.
  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.

Topics: Java Back-end