Chain processing of requests in behavioral patterns - chain of responsibility pattern

complete solution

In order to make the approval process of the purchase order more flexible and realize the chain transmission and processing of the purchase order, the developers of Sunny use the chain of responsibility model to realize the hierarchical approval of the purchase order. The basic structure is shown in the figure:

In the figure, the abstract class Approver acts as an abstract handler (abstract deliverer), Director, VicePresident, President and Congress act as concrete handlers (concrete deliverer), and PurchaseRequest acts as a request class. The complete code looks like this:

//Purchase Order: Request Class
class PurchaseRequest {
        private double amount;    //Purchase amount
        private int number;        //Purchase order number
        private String purpose;        //Purchasing purpose
        public PurchaseRequest(double amount, int number, String purpose) {
            this.amount = amount;
            this.number = number;
            this.purpose = purpose;
        }

        //get,set method omitted

}
//Approver Class: Abstract Handler
abstract class Approver {
        protected Approver successor; //define successor object
        protected String name; //Approver Name

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

        //set successor
        public void setSuccessor(Approver successor) {
            this.successor = successor;
        }

        //abstract request handler
        public abstract void processRequest(PurchaseRequest request);
}
    //Director class: specific handler 
    class Director extends Approver {
        public Director(String name) {
            super(name);
        }

        //Specific request processing method 
        public void processRequest(PurchaseRequest request) {
            if (request.getAmount() < 50000) {
                System.out.println("director" + this.name + "To approve a purchase order:" + request.getNumber() + ",Amount:" + request.getAmount() + "Yuan, purchase purpose:" + request.getPurpose() + ". ");
                //process the request
            } else {
                this.successor.processRequest(request);
                //forward request 
            }
        }
    }

    //Vice-chairman category: specific handler
    class VicePresident extends Approver {
        public VicePresident(String name) {
            super(name);
        }

        //Specific request processing method 
        public void processRequest(PurchaseRequest request) {
            if (request.getAmount() < 100000) {
                System.out.println("Vice Chairman" + this.name + "To approve a purchase order:" + request.getNumber() + ",Amount:" + request.getAmount() + "Yuan, purchase purpose:" + request.getPurpose() + ". ");
                //process the request 
            } else {
                this.successor.processRequest(request);
                //forward request 
            }
        }
    }

    //Chairman category: specific handler 
    class President extends Approver {
        public President(String name) {
            super(name);
        }

        //Specific request processing method
        public void processRequest(PurchaseRequest request) {
            if (request.getAmount() < 500000) {
                System.out.println("Chairman" + this.name + "To approve a purchase order:" + request.getNumber() + ",Amount:" + request.getAmount() + "Yuan, purchase purpose:" + request.getPurpose() + ". ");
                //process the request
            } else {
                this.successor.processRequest(request);
                // forward request 
            }
        }
    }

    //Board Class: Specific Handlers 
    class Congress extends Approver {
        public Congress(String name) {
            super(name);
        }
        //Specific request processing method 
                       /

        public void processRequest(PurchaseRequest request) {
            System.out.println("To hold the board of directors to approve the purchase order:" + request.getNumber() + ",Amount:" + request.getAmount() + "Yuan, purchase purpose:" + request.getPurpose() + ". ");
            //process the request
        }
    }

Write the following client test code:

class Client {
        public static void main(String[] args) {
            Approver wjzhang, gyang, jguo, meeting;
            wjzhang = new Director("Zhang Wuji");
            gyang = new VicePresident("Yang Guo");
            jguo = new President("Guo Jing");

            meeting = new Congress("Board of Directors");
            //Create a chain of responsibility
            wjzhang.setSuccessor(gyang);
            gyang.setSuccessor(jguo);
            jguo.setSuccessor(meeting);
            //Create purchase order
            PurchaseRequest pr1 = new PurchaseRequest(45000, 10001, "buy Etienne sword");
            wjzhang.processRequest(pr1);
            PurchaseRequest pr2 = new PurchaseRequest(60000, 10002, "Buy "Sunflower Collection"");
            wjzhang.processRequest(pr2);
            PurchaseRequest pr3 = new PurchaseRequest(160000, 10003, "Buy the Diamond Sutra");
            wjzhang.processRequest(pr3);
            PurchaseRequest pr4 = new PurchaseRequest(800000, 10004, "Buy Peach Blossom Island");
            wjzhang.processRequest(pr4);
        }
}

Compile and run the program, the output is as follows:

Director Zhang Wuji approves the purchase order: 10001, amount: 45000.0 Yuan, purchase purpose: buy Yitian sword.
Vice Chairman Yang Guo approves the purchase order:10002,Amount: 60000.0 Yuan, purchase purpose: to buy "Sunflower Collection".
Chairman Guo Jing approves the purchase order:10003,Amount: 160000.0 Yuan, purchase purpose: to purchase the Diamond Sutra.  
To hold the board of directors to approve the purchase order:10004,Amount: 800000.0 Yuan, purchase purpose: to buy Peach Blossom Island.

 

Chain of Responsibility Pattern Summary

The Chain of Responsibility pattern organizes request handlers by establishing a chain. Requests will be passed along the chain. The request sender does not need to know when, where and how the request is processed, thus realizing the decoupling of the request sender and handler. . In software development, if there are multiple objects that can process the same request, the chain of responsibility pattern can be applied. For example, in Web application development, a filter chain is created to filter the request data and implemented in the workflow system. The hierarchical approval of official documents, etc., the use of the chain of responsibility model can better solve such problems.

 

The main advantages of the Chain of Responsibility pattern are as follows:

(1) The responsibility chain mode makes it unnecessary for an object to know which other object handles its request. The object only needs to know that the request will be processed. Neither the receiver nor the sender has clear information about the other party, and the objects in the chain are not It is necessary to know the structure of the chain, and the client is responsible for the creation of the chain, which reduces the coupling degree of the system.

(2) The request processing object only needs to maintain a reference to its successor without maintaining its references to all candidate handlers, which can simplify the interconnection of objects.

(3) When assigning responsibilities to objects, the chain of responsibility can give us more flexibility, and the responsibilities of processing a request can be added or changed by dynamically adding or modifying the chain at runtime.

(4) When adding a new specific request handler to the system, there is no need to modify the code of the original system, but only need to rebuild the chain on the client side. From this point of view, it conforms to the "open-closed principle".

 

The main disadvantages of the Chain of Responsibility pattern are as follows:

(1) Since a request does not have a clear recipient, there is no guarantee that it will be processed, and the request may not be processed until the end of the chain; a request may also be processed because the chain of responsibility is not properly configured to processing.

(2) For a relatively long chain of responsibility, the processing of the request may involve multiple processing objects, the system performance will be affected to a certain extent, and it is inconvenient to debug the code.

(3) If the chain is not established properly, it may cause circular calls, which will cause the system to fall into an infinite loop.

 

Consider using the Chain of Responsibility pattern in the following situations:

(1) There are multiple objects that can process the same request. The specific object to process the request will be determined at runtime. The client only needs to submit the request to the chain, and does not need to care who is the processing object of the request and how it is processed. of.

(2) Submit a request to one of multiple objects without explicitly specifying the recipient.

(3) A group of objects can be dynamically specified to process requests, the client can dynamically create a chain of responsibility to process requests, and can also change the order of processors in the chain.

Tags: Design Pattern

Posted by Catharsis on Wed, 11 May 2022 10:24:14 +0300