Small knowledge, big challenge! This paper is participating in theEssentials for programmers”Creative activities

preface

This pattern is basically a necessary framework of a design pattern, whether Netty or Spring, the most classic AOP also embodies this design pattern, this design pattern is not very difficult to learn, but also easier to see the specific use of the way.

define

Chain of responsibility pattern can be seen as for decoupling requests and processing, such as commonly used interceptor framework is to decouple the request and deal with, we only in accordance with the specification for the same interface, at the same time configuration Bean can “insert” like a blade server after our own defined rules, because we design different rules have different interception effect, So this design pattern is a “behavioral pattern.”

As for the chain of responsibility design pattern, it is often used in work such as verification, auditing or blocking processing, as well as some text filtering, etc. Let’s take a look at how it is designed:

The advantages and disadvantages

Advantages:

  1. The handler and sender of the request are decoupled, and the handler does not need to care about how the sender sends the request, but only needs to focus on and process its own logic.
  2. The order of request processing can be defined and combined freely, which improves the reuse of request processing code.

Disadvantages:

  1. The chain of responsibility may lose the handler of the request because it does not know who the handler of the request is.
  2. If the chain of responsibility is too long, and if the intermediate processing time is too long, it will affect the efficiency of the overall request and processing
  3. The key lies in the configuration of the client. If the client is incorrectly configured, it may cause inexplicable problems, such as character processing after encoding processing, or data processing order is not equal

The first implementation: unified scheduling

The first implementation is simpler and easier to understand, and is a bit like registering listeners and distributing requests to each listener,

Standard interface: The common method of standard interface is handler(). The subclass is responsible for implementing the interface and then calling it through the responsibility chain scheduling center to unify the standard interface.

Specific handler: that is, the handler that is coupled to the request and processing described above. The handler does not need to care if the call to

Responsibility processing center: mainly responsible for internal scheduling and transmission of responsibility chain, etc., of course, it can also be similar to interception processing.

Client: register specific interception processing objects, which are processed by the responsibility processing center in a unified manner, and mainly conduct interactive scheduling with the client.

Below we are based on a simple addition, subtraction, multiplication and division number scheduler for responsible mode template code.

Request processing interface:

The request processing interface defines two numeric parameters and returns the processing result

public interface Request {

   /** * The responsibility chain specification interface *@paramVal1 Parameter 1 *@paramVal1 parameter 2 *@return* /
   int process(int val1, int val2);
}
Copy the code

Dispatch center

The scheduling center of the responsibility chain is mainly responsible for the scheduling and processing of requests, and the array form is used here to maintain the whole scheduling process.

public class RequestChain {

    private int index;

    private Request[] requestList;

    public RequestChain(int index) {
        this.index = 0;
        this.requestList = new Request[index];
    }

    public void addRequest(Request request) {
        if (index >= requestList.length) {
            throw new UnsupportedOperationException("It is full and cannot be added.");
        }
        requestList[index++] = request;
    }

    public boolean process(int val1, int val2) {
        int result = 0;
        for (Request req : requestList) {
            try {
                result += req.process(val1, val2);
            } catch (Exception e) {
                System.out.printf("Processing failure %s, processing failure %s%n", index, req);
                return false;
            }

        }
        System.out.printf("Result :%s\n", result);
        return true; }}Copy the code

The specific implementation

The specific implementation code is as follows, the following is related to the addition and division and subtraction processing:

public class DevideRequest implements Request{
    @Override
    public int process(int val1, int val2) {
        if(0 == val2){
            throw new IllegalArgumentException("The divisor cannot be zero.");
        }
        return new BigDecimal(val1).divide(newBigDecimal(val2)).intValue(); }}Copy the code
public class AddRequest implements Request{


    @Override
    public int process(int val1, int val2) {
        returnval1 + val2; }}Copy the code
public class SubstractRequest implements Request {
    @Override
    public int process(int val1, int val2) {
        returnval1 - val2; }}Copy the code

Finally, the code for unit tests:

public class Main {

    public static void main(String[] args) {
        RequestChain requestChain = new RequestChain(3);
        requestChain.addRequest(new AddRequest());
        requestChain.addRequest(new SubstractRequest());
        requestChain.addRequest(new DevideRequest());
        requestChain.process(15.6); }}Copy the code

This part of the code is easier to understand, let’s take a look at the “change” version of the chain of responsibility mode, the main change is to use a similar form of linked list to switch processing in the call center, the specific code is as follows.

The second implementation: abstract handler

Abstract handler and the above distribution form is slightly different, first of all, the dispatch center from a single class to abstract interface to abstract class form processing, by defining the form of abstract method, let the concrete request processing object to deal with the next forward object.

Responsibility chain abstract scheduling center: responsible for defining the forwarding rules of the lower level concrete implementation scheduler and defining the unified request logic processing specification

Specific processing scheduling object: inherit the abstract scheduling center at the same time, need to call the method of the scheduling center forward request processing to the next handler, so as to realize the forwarding operation of request processing, after the implementation of the processing method to achieve their own processing logic.

Abstract handler

The abstract handler replaces the responsible call center and mainly provides a way to forward the next requester and an abstract request handler that must be implemented by the concrete implementer.

// Abstract the handler role
abstract class Handler {
    private Handler next;

    public void setNext(Handler next) {
        this.next = next;
    }

    public Handler getNext(a) {
        return next;
    }

    // How to handle requests
    public abstract void handleRequest(String request);
}


Copy the code

The specific implementation

In the concrete implementation, as the implementation layer, the request is forwarded to the next handler, so it can be found that the request handlers are mutually aware of the next handler, but not of the previous handler.


// Specify handler role 1
class ConcreteHandler1 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("one")) {
            System.out.println(Handler 1 is responsible for processing the request!);
        } else {
            if(getNext() ! =null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("No one is processing this request!"); }}}}// Specify handler role 2
class ConcreteHandler2 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("two")) {
            System.out.println("Handler 2 is responsible for processing the request!");
        } else {
            if(getNext() ! =null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("No one is processing this request!"); }}}}Copy the code

Here is the specific unit test code:

public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        // Assemble responsibility chain
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setNext(handler2);
        // Submit the request
        handler1.handleRequest("two"); }}Copy the code

conclusion

The chain of responsibility mode is less written by itself, but the framework is used more, as long as you are familiar with the template code related to the chain of responsibility mode.

Write in the last

Common design patterns have been covered in previous articles, and some of the more obscure ones will be covered later.