Responsibility chain pattern of java design pattern (in serial...)

Responsibility chain model of java design pattern (two-way)

preface

This paper introduces the responsibility chain pattern in java design pattern, which is also called responsibility chain pattern. Starting from the actual needs, explain why to use this mode and what its advantages and disadvantages are.

1, Concept

It is a kind of behavior pattern. In the responsibility chain pattern, many objects are connected by each object's reference to its next home 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 know which object in the chain will eventually process the request, which makes the system dynamically reorganize and allocate responsibilities without affecting the client.
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.
This paper is not a single direction responsibility chain in the traditional sense, but a two-way responsibility chain.

2, Role

1. Abstract handler

Define an interface to handle requests. If necessary, the interface can define a method to set and return a reference to the next home. This role is usually implemented by a Java abstract class or Java interface. The aggregation relationship of the Handler class gives the reference of the specific subclass to the next family, and the abstract method handleRequest() standardizes the subclass's operation of processing requests.

2. Concrete handler

After receiving the request, the specific handler can choose to dispose of the request or send the request to the next home. Since the specific handler holds a reference to the next home, the specific handler can access the next home if necessary.

3. Customer (Client)

Create a processing chain and submit a request to the specific handler object at the chain head. It doesn't care about the processing details and the transmission process of the request.

This article may not be written completely according to the above role description. The design patterns I understand are not necessarily written according to the specified things, but mainly understand the ideas.

3, Demand

Suppose there is a receipt requirement, as shown in the figure below:

Receipt document:

fieldremarks
idString, primary key
typeint, type
goodsIdItem primary key
approveIdString, approver
approveStatusint, approval status
statusint, document status
package com.gh.freemarker.handler;

/**
 * Class function description: receipt entity
 **/
public class InStoreDTO {

    /**
     * Primary key
     */
    private String id;

    /**
     * type
     */
    private Integer type;

    /**
     * Item primary key
     */
    private String goodsId;

    /**
     * Approver
     */
    private String approveId;

    /**
     * Approval status
     */
    private Integer approveStatus;

    /**
     * Document Status 
     */
    private Integer status;
	//... omit the get set method.
}

Document warehousing process:

  1. Doc type = 1 direct receipt; otherwise, step 2.
  2. If the document is A special process, it needs to be submitted to A for approval. Otherwise, step 3.
  3. Judge whether the warehousing level of the article meets the conditions and meets the warehousing requirements, otherwise submit the document to B for approval.

A. approval process:

  1. A is approved and directly warehoused. End without passing.

B. approval process

  1. B. if it is approved, step 6 shall be implemented, and if it is not approved, it shall be ended.
  2. Judge whether an attribute of an article is A special value. If not, submit it to A for approval. Otherwise, stock in.

Because it is a case requirement, the description of steps 3 and 6 is not specific, which can be understood as calling a method.

1. Thinking

The above requirements may not be particularly complex (the real requirements will be very complex), but if we program directly, there will be many if else code blocks. Although it can also be implemented, it is not very easy to maintain. Assuming that one or more node judgments will be added in the middle of the process in the future, we will have a headache when we face a pile of if else.
Therefore, the responsibility chain model in this paper can be used. We can abstract each judgment node into a specific handler. The specific handler only needs to pay attention to its own business logic and jump to the specific handler upstream (judgment condition is Y) or downstream (judgment condition is N). If the requirements change in the future, we only need to add or modify specific upstream and downstream processors.
,

2. Realization

Through the above thinking, we can see that there are roughly three processes: warehousing process and A or B approval process. We can abstract them into two methods, one is warehousing method and the other is approval method.
For specific handlers, please see the following specific classes.

2.1 creating an abstract handler

/**
 * Class function description: Abstract handler
 **/
public abstract class AbstractHandler<T> {
    /**
     * Y Branch processor
     */
    protected AbstractHandler<T> yes;
    /**
     * N Branch processor
     */
    protected AbstractHandler<T> no;

    /**
     * Processing entry, public method
     * @param obj Object to be processed
     * @return
     */
    public boolean handler(T obj){
        AbstractHandler<T> nextHandler = null;
        if(customHandler(obj)){
            nextHandler = getYes();
        }else{
            nextHandler = getNo();
        }
        if(nextHandler != null){
           return nextHandler.handler(obj);
        }
        return true;
    }

    /**
     *  Business processing method of specific processor
     * @param obj Object to be processed
     * @return
     */
    protected abstract boolean customHandler(T obj);

    public AbstractHandler<T> getYes() {
        return yes;
    }

    public void setYes(AbstractHandler<T> yes) {
        this.yes = yes;
    }

    public AbstractHandler<T> getNo() {
        return no;
    }

    public void setNo(AbstractHandler<T> no) {
        this.no = no;
    }

}	

2.2 specific processor - > type judgment node

/**
 * Class function description: type = 1, go to yes handler InStoreHandler, otherwise go to no handler SpecialProcessHandler
 **/
public class TypeHandler extends AbstractHandler<InStoreDTO> {

    public TypeHandler(){
        setYes(new InStoreHandler());
        setNo(new SpecialProcessHandler());
    }


    @Override
    protected boolean customHandler(InStoreDTO obj) {
        return 1 == obj.getType();
    }
}

2.3 specific processor - > receipt node

public class InStoreHandler extends AbstractHandler<InStoreDTO> {

	//There is no next node, so there is no constructor
    @Override
    protected boolean customHandler(InStoreDTO obj) {
        System.out.println(String.format("%s Warehousing succeeded",obj.getId()));
        return true;
    }
}

2.4 specific handler - > special process node

/**
 * Class function description: special process handler: If yes, it will be submitted to A for approval; otherwise, it will be submitted to the item authority level handler
 **/
public class SpecialProcessHandler extends AbstractHandler<InStoreDTO> {

    private static final Random random = new Random();

    public SpecialProcessHandler(){
        setYes(new AApproveHandler());
        setNo(new GoodsAccessLevelHandler());
    }


    @Override
    protected boolean customHandler(InStoreDTO obj) {
        System.out.println(String.format("%s Special process query",obj.getId()));
        //Simulated service
        return random.nextInt(100) %2 == 0;
    }
}

2.5 specific processor – > a approval node

/**
 * Class function description: generates document information approved by A
 **/
public class AApproveHandler extends AbstractHandler<InStoreDTO> {

    @Override
    protected boolean customHandler(InStoreDTO obj) {
        //Modify the document approval information for approval by A
        obj.setApproveId("A");
        obj.setApproveStatus(0);
        return true;
    }
}

2.6 specific handler - > item permission level node

/**
 *
 * Class function description: item permission level processing. It is used to query whether the permission of the item is higher than the level required by the business. If it is higher, it will be directly warehoused. Otherwise, it will be submitted to B for approval
 **/
public class GoodsAccessLevelHandler extends AbstractHandler<InStoreDTO> {

    public GoodsAccessLevelHandler(){
        setYes(new InStoreHandler());
        setNo(new BApproveHandler());
    }

    @Override
    protected boolean customHandler(InStoreDTO obj) {
        System.out.println(String.format("According to[%s]Query permission level",obj.getGoodsId()));

        return searchLevel(obj.getGoodsId());
    }

    /**
     * Analog service: if it is 1, it proves high, otherwise it is low
     * @param goodsId Item primary key
     * @return
     */
    private boolean searchLevel(String goodsId) {
        return goodsId.equals("1");
    }
}

2.7 specific processor - > b approval node

/**
 *
 * Class function description: generates document information approved by B
 **/
public class BApproveHandler extends AbstractHandler<InStoreDTO> {
	//There is no next node, so you don't need a constructor. You need to go through the approval interface
    @Override
    protected boolean customHandler(InStoreDTO obj) {
        //Modify the document approval information for approval by B
        obj.setApproveId("B");
        obj.setApproveStatus(0);
        return true;
    }
}

2.8 specific handler - > approval reject node

public class ApproveRejectHandler extends AbstractHandler<InStoreDTO> {
	//There is no next node, so there is no constructor
    @Override
    protected boolean customHandler(InStoreDTO obj) {
        //Modify document approval information
        obj.setApproveStatus(2);
        return true;
    }
}

2.9 specific handler – > the item's attribute is a special value node

/**
 * Class function description: item special attribute handler: If yes, it will be submitted to A for approval; otherwise, it will be warehoused
 **/
public class GoodsSpecialPropertiesHandler extends AbstractHandler<InStoreDTO> {

    private static final Random random = new Random();

    public GoodsSpecialPropertiesHandler(){
        setYes(new AApproveHandler());
        setNo(new InStoreHandler());
    }


    @Override
    protected boolean customHandler(InStoreDTO obj) {
        System.out.println(String.format("%s Special attribute query",obj.getGoodsId()));
        //Simulated service
        return random.nextInt(100) %2 == 0;
    }
}

2.9 responsibility chain manager

We can create a manager to expose to the client, which defines the specific handler at the beginning of the responsibility chain.

public class HandlerManager<T> {
	//Set processor to start
    private AbstractHandler<T> first;

    private HandlerManager(AbstractHandler<T> first){
        this.first = first;
    }

    public static <T> HandlerManager<T> getInstance(AbstractHandler<T> first){
        return new HandlerManager<>(first);
    }

    public boolean handler(T obj){
        return first.handler(obj);
    }

}

2.10 warehousing interface

/**
 *
 * Class function description: Warehousing interface
 **/
public interface IInStoreFlow {

    /**
     * Warehousing method
     * @param inStoreDTO Warehousing order
     * @return boolean
     */
    boolean inStore(InStoreDTO inStoreDTO);

    /**
     * Function Description: approve receipt doc
     * @param inStoreDTO Warehousing order
     * @param approveId Approver
     * @param approveStatus Approval status 1 succeeded 2 failed
     * @return boolean
     **/
    boolean approveInStoreDTO(InStoreDTO inStoreDTO,String approveId,int approveStatus);
}

2.11 warehousing realization

/**
 *
 * Class function description: Warehousing interface
 **/
public class InStoreFlow implements IInStoreFlow {

    /**
     *  The receipt process starts with the type handler
     * @param inStoreDTO Warehousing order
     * @return
     */
    @Override
    public boolean inStore(InStoreDTO inStoreDTO) {
        return HandlerManager.getInstance(new TypeHandler()).handler(inStoreDTO);
    }

    /**
     *  If A approves and directly executes the warehousing process, B approves and executes the item special attribute processing, otherwise, the approval is rejected.
     * @param inStoreDTO Warehousing order
     * @param approveId Approver
     * @param approveStatus Approval status 1 succeeded 2 failed
     * @return
     */
    @Override
    public boolean approveInStoreDTO(InStoreDTO inStoreDTO, String approveId, int approveStatus) {
        AbstractHandler<InStoreDTO> abstractHandler;
        if("A".equals(approveId) && approveStatus == 1){
            abstractHandler = new InStoreHandler();
        }else if("B".equals(approveId) && approveStatus == 1) {
            abstractHandler = new GoodsSpecialPropertiesHandler();
        }else {
            abstractHandler = new ApproveRejectHandler();
        }
        return HandlerManager.getInstance(abstractHandler).handler(inStoreDTO);
    }

}

Specific call to be supplemented
. . .

Now that all classes related to this requirement have been created, we mainly introduce the idea of this pattern.
If the demand changes and a judgment needs to be added, we only need to add a specific handler and add it to the corresponding Y or N branch.

summary

To be added

Tags: Java Design Pattern

Posted on Tue, 30 Nov 2021 12:08:40 -0500 by squiggerz