Responsibility chain model of design model

Time:2022-5-23

The responsibility chain model is also the competent responsibility chain model, which belongs to the behavior model; In the responsibility chain model, many objects are connected by each object’s reference to its next family to form a chain. Requests are passed along the chain until an object in the chain decides to process the request. The client issuing the request does not guide which object in the chain will finally process the request, which makes the system dynamically reorganize the chain and assign responsibilities without affecting the client.

The responsibility chain model reduces the coupling between the sender and receiver of the request, so that multiple objects have the opportunity to process the request. A chain can be a line, a tree, or a ring. The topology of the chain can be simply connected or multi connected. The responsibility chain model does not specify the topology of the responsibility chain. However, the responsibility chain model requires that at the same time, orders can only be sent to one lower house (or disposed of), not more than one lower house.

There are two situations in the responsibility chain model.

  1. Pure responsibility chain mode: a request must be received by a handler object, and a specific handler can only adopt one of the following two behaviors for processing a request: self processing (assuming responsibility); Shift the responsibility to the next family.
  2. Impure responsibility chain mode: it allows a specific handler object to transfer the remaining responsibility to the next home after assuming part of the responsibility of the request, and a request can not be received by any receiving end object.

The UML class diagram of the responsibility chain pattern is as follows:

As can be seen from the above figure, the responsibility chain model involves three roles: Abstract handler role, specific handler role and customer role:

  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 doesn’t care about the processing details and the transmission process of the request.

Examples of OA purchase approval

Requirements for procurement approval project of OA system of a school:

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 president

If the amount is less than or equal to 30000, it shall be approved by the vice president

If the amount exceeds 30000, it shall be approved by the president

For such requirements, the responsibility chain model can be used. The UML class diagram is as follows:

Request:

package com.charon.responsibility;

/**
 * @className: PurchaseRequest
 * @description:
 * @author: charon
 * @create: 2022-04-10 22:45
 */
public class PurchaseRequest {

    /**
     *Request number
     */
    private String id;

    /**
     *Amount
     */
    private double price;

    public PurchaseRequest(String id, double price) {
        this.id = id;
        this.price = price;
    }

    /**
     * Gets the value of id
     *
     * @return the value of id
     */
    public String getId() {
        return id;
    }

    /**
     * Gets the value of price
     *
     * @return the value of price
     */
    public double getPrice() {
        return price;
    }
}

Abstract processor:

package com.charon.responsibility;

/**
 * @className: Approver
 *@ Description: Abstract handler
 * @author: charon
 * @create: 2022-04-10 22:43
 */
public abstract class Approver {

    /**
     *Next processor
     */
    private Approver Approver;

    /**
     *Name
     */
    private String name;

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

    /**
     * Sets the Approver
     *
     * @param approver Approver
     */
    public void setApprover(Approver approver) {
        Approver = approver;
    }

    /**
     * Gets the value of Approver
     *
     * @return the value of Approver
     */
    public com.charon.responsibility.Approver getApprover() {
        return Approver;
    }

    /**
     * Gets the value of name
     *
     * @return the value of name
     */
    public String getName() {
        return name;
    }

    /**
     *Method of handling approval
     * @param request
     */
    abstract void processRequest(PurchaseRequest request);
}

Specific handler:

package com.charon.responsibility;

/**
 * @className: DepartmentApprover
 * @description:
 * @author: charon
 * @create: 2022-04-10 22:52
 */
public class DepartmentApprover extends Approver{

    public DepartmentApprover(String name) {
        super(name);
    }

    @Override
    void processRequest(PurchaseRequest request) {
        if(request.getPrice() <= 5000){
            System. out. Println ("request No.: + request. Getid() +" by "+ this Getname() + "processing");
        }else{
            this.getApprover().processRequest(request);
        }
    }
}

package com.charon.responsibility;

/**
 * @className: CollegeApprover
 * @description:
 * @author: charon
 * @create: 2022-04-10 22:46
 */
public class CollageApprover extends Approver{

    public CollageApprover(String name) {
        super(name);
    }

    @Override
    void processRequest(PurchaseRequest request) {
        if(request.getPrice() > 5000 && request.getPrice() <= 10000){
            System. out. Println ("request No.: + request. Getid() +" by "+ this Getname() + "processing");
        }else{
            this.getApprover().processRequest(request);
        }
    }
}


package com.charon.responsibility;

/**
 * @className: ViceSchoolApprover
 * @description:
 * @author: charon
 * @create: 2022-04-10 22:53
 */
public class ViceSchoolApprover extends Approver{

    public ViceSchoolApprover(String name) {
        super(name);
    }

    @Override
    void processRequest(PurchaseRequest request) {
        if(request.getPrice() > 10000 && request.getPrice() <= 30000){
            System. out. Println ("request No.: + request. Getid() +" by "+ this Getname() + "processing");
        }else{
            this.getApprover().processRequest(request);
        }
    }
}

package com.charon.responsibility;

/**
 * @className: SchoolMasterApprover
 * @description:
 * @author: charon
 * @create: 2022-04-10 22:53
 */
public class SchoolMasterApprover extends Approver{

    public SchoolMasterApprover(String name) {
        super(name);
    }

    @Override
    void processRequest(PurchaseRequest request) {
        System. out. Println ("request No.: + request. Getid() +" by "+ this Getname() + "processing");
    }
}

Client test:

package com.charon.responsibility;

/**
 * @className: Client
 * @description:
 * @author: charon
 * @create: 2022-04-10 22:42
 */
public class Client {

    public static void main(String[] args) {
        PurchaseRequest request1 = new PurchaseRequest("1", 3500);
        //Create approver
        Departmentapprover = new departmentapprover ("director Zhang San");
        Collageapprover collageapprover = new collageapprover ("President Li Si");
        Vicescool approver vicescool approver = new vicescool approver ("vice president Wang Wu");
        Schoolmasterapprover schoolmasterapprover = new schoolmasterapprover ("headmaster Zhao Liu");

        //Set up the approval process
        departmentApprover.setApprover(collageApprover);
        collageApprover.setApprover(viceSchoolApprover);
        viceSchoolApprover.setApprover(schoolMasterApprover);

        departmentApprover.processRequest(request1);

        // viceSchoolApprover.processRequest(request1);
    }
}

Print:
    The request No.: 1 was handled by director Zhang San

The main advantages of the responsibility chain model are as follows:

  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 the clear information of each other.
  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 clarified and in line with the principle of single responsibility of the class.

The main disadvantages of the responsibility chain model 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.

Application scenario of pattern

  1. Multiple objects can handle a request, but the specific object that handles the request is automatically determined at run time.
  2. You can dynamically specify a set of objects to process requests, or add new processors.
  3. You need to submit a request to one of multiple processors without explicitly specifying the request processor.