Design pattern - responsibility chain pattern

Procurement approval project requirements of school OA system

Purchaser purchases teaching equipment

  1. If the amount is less than or equal to 5000, it shall be approved by the teaching Director (0 < = x < = 5000)
  2. If the amount is less than or equal to 10000, it shall be approved by the president (5000 < x < = 10000)
  3. If the amount is less than or equal to 30000, it shall be approved by the vice president (10000 < x < = 30000)
  4. If the amount exceeds 30000, it shall be approved by the president (30000 < x)

Please design procedures to complete the procurement approval items

1. Traditional solution OA system approval (class diagram)

2. Analysis of traditional solutions for OA system approval

  1. The traditional method is to call the corresponding Approver to complete the approval according to the purchase amount after receiving a purchase request.
  2. Traditional problem analysis: the client will use branch judgment (such as switch) to process different purchase requests, so there are the following problems: (1) if the approval amount of personnel at all levels changes, it also needs to change at the client; (2) the client must clearly know how many approval levels and access points there are
  3. In this way, there is a strong coupling relationship between the processing of a purchase request and the Approver, which is not conducive to code expansion and maintenance
  4. Solution = responsibility chain model

1, Responsibility chain model

1. Basic introduction

  1. The Chain of Responsibility Pattern, also known as the responsibility chain pattern, creates a chain of receiver objects for requests (simple diagram). This mode decouples the sender and receiver of the request.
  2. In the responsibility chain pattern, each recipient usually contains a reference to another recipient. If an object cannot process the request, it passes the same request to the next recipient, and so on.
  3. This type of design pattern belongs to behavioral pattern

2. Schematic class diagram of responsibility chain mode

  • Description of schematic class diagram - i.e. (roles and responsibilities of responsibility chain model)
  1. Handler: an abstract handler, which defines an interface for processing requests and means another handler
  2. Concretehandlera and B are specific handlers. They handle requests in their own charge and can access their successors (i.e. the next handler). If they can handle the current request, they will handle it. Otherwise, they will hand over the request to a successor for processing, so as to form a responsibility chain
  3. Request, which means many attributes, represents a request

3. The responsibility chain mode solves the OA system procurement approval

  1. Application example requirements
    Write procedures to complete the procurement approval project of school OA system: the purchaser needs to purchase teaching equipment
    If the amount is less than or equal to 5000, it shall be approved by the teaching director. If the amount is less than or equal to 10000, it shall be approved by the dean

  2. Train of thought analysis and illustration (class diagram)

Code implementation:

  • Approver

    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. The processing is completed by subclasses, so the method is made abstract
        public abstract void processRequest(PurchaseRequest purchaseRequest);
    }
    
  • DepartmentApprover implements the Approver abstract class

    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);
            }
        }
    }
    
  • College Approver implements the Approver abstract class

    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);
            }
        }
    }
    
  • The abstract class of Approver implemented by vicescoolmasterapprover

    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);
            }
        }
    }
    
    
  • SchoolMasterApprover implements the Approver abstract class

    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);
            }
        }
    }
    
  • PurchaseRequest

    //Request class
    public class PurchaseRequest {
    
        private int type = 0; //Request type
        private float price = 0.0f; //Requested amount
        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;
        }
    }
    
  • 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 Colonel Wang"); 
            SchoolMasterApprover schoolMasterApprover = new SchoolMasterApprover("Principal Tong");
    
            //You need to set the next of each approval level (handler:) 
            departmentApprover.setApprover(collegeApprover); 
            collegeApprover.setApprover(viceSchoolMasterApprover); 
            viceSchoolMasterApprover.setApprover(schoolMasterApprover); 
            schoolMasterApprover.setApprover(departmentApprover);
    
            //departmentApprover.processRequest(purchaseRequest); 
            viceSchoolMasterApprover.processRequest(purchaseRequest);
        }
    }
    
    

2, Application pattern of MVC in spring

  1. The spring MVC - handlerexecutionchain class uses the responsibility chain pattern

  2. Spring MVC request flow diagram

  3. Code analysis + Debug source code + description

    explain:

    protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HandlerExecutionChain mappedHandler = null;
        mappedHandler = getHandler(processedRequest);//Get HandlerExecutionChain object
        //In mappedhandler Handlerinterceptor obtained from applyprehandle
        //Interceptor called 	 interceptor.preHandle
        if (!mappedHandler.applyPreHandle(processedRequest, response)) { 
            return;
        }
    
        //Description: mappedhandler The applyposthandle method obtains the interceptor internally and calls
        //Interceptor 	 interceptor.postHandle(request, response, this.handler, mv);
        mappedHandler.applyPostHandle(processedRequest, response, mv);
    }
    
    //Description: in 	 mappedHandler. Inside applyprehandle,
    //	Also called 	 The triggerAfterCompletion method is invoked in this method.
    HandlerInterceptor interceptor = getInterceptors()[i]; 
    try {
        interceptor.afterCompletion(request, response, this.handler, ex);
    }
    catch (Throwable ex2) {
        logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
    }
    
    
  4. Summary of source code

    • In the flow chart of spring MVC request, the interceptor related method interceptor is executed Prehandler, wait
    • When processing spring MVC requests, we use the responsibility chain pattern and the adapter pattern
    • HandlerExecutionChain is mainly responsible for the execution and request processing of the request interceptor, but it does not process the request itself, but only assigns the request to the registered processor on the chain for execution. This is the implementation method of the responsibility chain, reduces the coupling between the responsibility chain itself and the processing logic, and standardizes the processing flow
    • HandlerExecutionChain maintains a collection of handlerinterceptors to which corresponding interceptors can be registered

3, Precautions and details of responsibility chain model

  1. Separate the request and processing to realize decoupling and improve the flexibility of the system
  2. The object is simplified so that the object does not need to know the structure of the chain
  3. The performance will be affected, especially when the chain is relatively long. Therefore, it is necessary to control the maximum number of nodes in the chain. Generally, set a maximum number of nodes in the Handler and judge whether the threshold has been exceeded in the setNext() method. If the threshold is exceeded, the chain is not allowed to be established to avoid the unintentional damage to the system performance caused by the super long chain
  4. Inconvenient debugging. Similar to recursion, the logic may be complex during debugging
  5. Best application scenario: when there are multiple objects that can process the same request, such as multi-level request, leave / salary increase approval process, Tomcat Encoding processing in Java Web, interceptor

Keywords: Design Pattern

Added by zildjohn01 on Sat, 15 Jan 2022 02:03:20 +0200