Chain of Responsibility definition: Chain of Responsibility (CoR) is a series of classes that try to process a request. These classes are a loose coupling. The only thing in common is passing a request between them. In other words, when a request comes, Class A processes first. If it is not processed, it is passed to Class B process. If it is not processed, it is passed to Class C process, and it is passed like a chain.
How to use the chain of responsibility model
Although this paragraph uses CoR, it also demonstrates what CoR is.
There is a Handler interface:
The code copy is as follows:
public interface Handler{
public void handleRequest();
}
This is an example of handling requests. If there are multiple requests, such as requesting help requests to print or request formatting:
◆ The first solution that comes to mind is: add multiple requests to the interface:
The code copy is as follows:
public interface Handler{
public void handleHelp();
public void handlePrint();
public void handleFormat();
}
Specifically, it is a code to implement the interface:
The code copy is as follows:
public class ConcreteHandler implements Handler{
private Handler successor;
public ConcreteHandler(Handler successor){
this.successor=successor;
}
public void handleHelp(){
//Specific code for processing the help request...
}
public void handlePrint(){
//If it is a print, turn to process Print
successor.handlePrint();
}
public void handleFormat(){
//If it is Format, go to process format
successor.handleFormat();
}
}
There are three such specific implementation classes, above, which are processing help, and processing Print and processing Format, which are probably our most commonly used programming ideas.
Although the idea is simple and clear, there is an extension problem. If we need to add another request type, we need to modify the interface and each implementation.
◆ The second solution: turn each request into an interface, so we have the following code:
The code copy is as follows:
public interface HelpHandler{
public void handleHelp();
}
public interface PrintHandler{
public void handlePrint();
}
public interface FormatHandler{
public void handleFormat();
}
public class ConcreteHandler
implements HelpHandler,PrintHandler,FormatHandlet{
private HelpHandler helpSuccessor;
private PrintHandler printSuccessor;
private FormatHandler formatSuccessor;
public ConcreteHandler(HelpHandler helpSuccessor,PrintHandler printSuccessor,FormatHandler formatSuccessor)
{
this.helpSuccessor=helpSuccessor;
this.printSuccessor=printSuccessor;
this.formatSuccessor=formatSuccessor;
}
public void handleHelp(){
.........
}
public void handlePrint(){this.printSuccessor=printSuccessor;}
public void handleFormat(){this.formatSuccessor=formatSuccessor;}
}
When adding a new request request, this method only saves the amount of modification of the interface, and the interface implementation of the ConcreteHandler also needs to be modified. And the code is obviously not simple and beautiful.
◆ Solution 3: Only one parameterization method is used in the Handler interface:
The code copy is as follows:
public interface Handler{
public void handleRequest(String request);
}
Then the Handler implementation code is as follows:
public class ConcreteHandler implements Handler{
private Handler successor;
public ConcreteHandler(Handler successor){
this.successor=successor;
}
public void handleRequest(String request){
if (request.equals("Help")){
//Here is the specific code for handling Help}else
//Pass to the next successor.handle(request);
}
}
}
Let's first assume that request is of String type. What if it is not? Of course we can create a special class Request
◆ The final solution: The code of the interface Handler is as follows:
The code copy is as follows:
public interface Handler{
public void handleRequest(Request request);
}
Definition of Request class:
public class Request{
private String type;
public Request(String type){this.type=type;}
public String getType(){return type;}
public void execute(){
//Request's real specific behavior code}
}
Then the Handler implementation code is as follows:
The code copy is as follows:
public class ConcreteHandler implements Handler{
private Handler successor;
public ConcreteHandler(Handler successor){
this.successor=successor;
}
public void handleRequest(Request request){
if (request instanceof HelpRequest){
//Here is the specific code for handling Help}else if (request instanceof PrintRequest){
request.execute();
}else
//Pass to the next successor.handle(request);
}
}
}
This solution is CoR. On a chain, there are corresponding responsibilities, so it is called Chain of Responsibility.
1. Advantages of CoR: Because it is impossible to predict which type of requests from the outside world belong to, if each class encounters a request that it cannot process, just give up. This undoubtedly reduces the coupling between classes.
2. The disadvantage of CoR is its inefficiency, because the completion of a request may have to be traversed until the end before it can be completed. Of course, it can also be optimized using the concept of a tree. In Java AWT1.0, the handling of mouse buttons is to use CoR. After entering Java.1.1, Observer is used instead of CoR.
The scalability is poor because in CoR, there must be a unified interface Handler. The limitations are here.