Definition: Allows multiple objects to have the opportunity to process the request, thus avoiding the coupling relationship between the sender and the receiver of the request. Connect these objects into a chain and pass the request along the chain until an object processes it.
Type: Behavioral Pattern
Class diagram:
Let’s first look at a piece of code:
public void test(int i, Request request){ if(i==1){ Handler1.response(request); }else if(i == 2){ Handler2.response(request); }else if(i == 3){ Handler3.response(request); }else if(i == 4){ Handler4.response(request); }else{ Handler5.response(request); } } The business logic of the code is as follows: the method has two parameters: the integer i and a request request. According to the value of i, who will handle the request, if i==1, it will be handled by Handler1, if i==2, it will be handled by Handler2, and so on. In programming, this kind of business processing method is very common. All classes that process requests include if...else... conditional judgment statements connected into a chain of responsibility to process the request. I believe everyone often uses it. The advantages of this method are that it is very intuitive, simple and clear, and relatively easy to maintain, but this method also has several headaches:
Code bloated: In actual applications, the judgment conditions are usually not so simple to determine whether it is 1 or 2. It may require complex calculations, maybe querying the database, etc. This will have a lot of extra code. If there are many judgment conditions, then this if...else... statement is basically impossible to read.
High coupling degree: If we want to continue to add classes that process requests, we must continue to add else if judgment conditions; in addition, the order of this condition is also written to the dead. If we want to change the order, we can only modify this condition statement.
Since we have already understood the shortcomings, we need to find a way to solve them. The business logic of this scenario is very simple: if condition 1 is met, it will be processed by Handler1, and if it is not met, it will be passed down; if condition 2 is met, it will be processed by Handler2, and if it is not met, it will be passed down, and so on until the end of the condition. In fact, the improvement method is also very simple, which is to put the part of the judgment conditions into the processing class. This is the principle of the responsibility connection model.
The structure of the responsibility company model
The class diagram of the responsibility-connected pattern is very simple, it consists of an abstractly processed class and its set of implementation classes:
Abstract processing class: The abstract processing class mainly includes a member variable nextHandler pointing to the next processing class and a method handRequest that handles the request. The main idea of the handRequest method is that if the processing conditions are met, this processing class will be processed, otherwise it will be processed by nextHandler.
Specific processing class: Specific processing class mainly implements the specific processing logic and applicable conditions for processing.
Example
The chain of responsibility model has two roles:
Abstract handler role: defines a requested interface. If necessary, you can define a method to set and return the reference to the next home object.
ConcreteHandler role: if it can be processed, process the request. If it cannot be processed, pass the request to the next home and let the next home handle it. That is to say, it handles requests it can handle and can access its next home.
The test code for the above pattern is as follows:
package chainOfResp;/** *Description: Abstract processing role*/public abstract class Handler { protected Handler successor; /** *Description: Processing method*/ public abstract void handlerRequest(String condition); public Handler getSuccessor() { return successor; } public void setSuccessor(Handler successor) { this.successor = successor; } } package chainOfResp;/** *Description: Detailed handling of roles*/public class ConcreteHandler1 extends Handler { @Override public void handlerRequest(String condition) { // If it is your own responsibility, you will handle it yourself and be responsible for passing it to the next home if(condition.equals("ConcreteHandler1")){ System.out.println( "ConcreteHandler1 handled "); return ; }else{ System.out.println( "ConcreteHandler1 passed "); getSuccessor().handlerRequest(condition); } }} package chainOfResp;/** *Description: Detailed handling of roles*/public class ConcreteHandler2 extends Handler { @Override public void handlerRequest(String condition) { // If it is your own responsibility, you will handle it yourself and be responsible for passing it to the next home if(condition.equals("ConcreteHandler2")){ System.out.println( "ConcreteHandler2 handled "); return ; }else{ System.out.println( "ConcreteHandler2 passed "); getSuccessor().handlerRequest(condition); } }} package chainOfResp;/** *Description: Detailed processing role*/public class ConcreteHandlerN extends Handler { /** * Here it is assumed that n is the last node of the chain that must be processed* In actual situations, a ring or a tree may appear, * This is not necessarily the last node. * */ @Override public void handlerRequest(String condition) { System.out.println( "ConcreteHandlerN handled"); }} package chainOfResp;/** *Description: Test class*/public class Client { /** *Description: */ public static void main(String[] args) { Handler handler1 = new ConcreteHandler1(); Handler handler2 = new ConcreteHandler2(); Handler handlern = new ConcreteHandlerN(); //Chain handler1.setSuccessor(handler2); handler2.setSuccessor(handlern); //Suppose this request is the responsibility of ConcreteHandler2 handler1.handlerRequest("ConcreteHandler2"); }}
To give this example, in the production workshop of a toy factory, the assembly line is a chain of responsibility. If a toy aircraft has a shell assembler, engine assembler, propeller assembler, and model packer. When the aircraft flows to whoever the object is flowing to, he will be responsible for installing the part he is responsible for. After this part is installed, it will flow to the next step and know that all environments are completed. This is a chain of responsibility that is generated. There is also a quality inspection chain, which is divided into multiple parts, shell inspection, engine inspection, propeller inspection, and packaging inspection. When the product is left to the inspector to test the piece he is responsible for, if there is any problem, it will be directly taken out. If there is no problem, it will be passed to the next inspector until all the tests are completed. These two are chains of responsibility, but the difference is that everyone will process the chain of responsibility and process part of it; while after judgment, the chain of responsibility for quality inspection will either be processed or not processed. These are the two categories of responsibility chains. The latter is called pure responsibility chains, and the former is called impure responsibility chains. Pure responsibility chains rarely exist in practical applications. The common one is impure responsibility chains. The above model simulates pure responsibility chains to handle.
Pros and cons of the responsibility chain model
Compared with if…else…, the responsibility chain pattern has a lower coupling ability because it distributes the conditional judgments into various processing classes, and the priority processing order of these processing classes can be set at will. The responsibility chain model also has its disadvantages, which is the same as the if...else... statement, that is, before finding the correct processing class, all judgment conditions must be executed. When the responsibility chain is relatively long, the performance problem is more serious.
Applicable scenarios for the chain of responsibility model
Just like the beginning example, if you feel overwhelmed when using the if…else… statement to organize a chain of responsibility and the code looks bad, you can use the chain of responsibility mode to refactor it.
Summarize
The responsibility chain model is actually a flexible version of if...else... statement. It puts these judgment conditions into each processing class. The advantage of this is that it is more flexible, but it also brings risks. For example, when setting up the relationship between the processing class before and after the processing class, you must be very careful to judge the relationship between the conditional logic before and after the processing class, and be careful not to have circular references in the chain.