Small knowledge, big challenge! This article is participating in the creation activity of “Essential Tips for Programmers”.
What is the chain of responsibility model
The client issues a request, and all the objects on the chain have a chance to process the request, without the client needing to know who the specific processing object is. This enables decoupling between requestor and receiver, and enables dynamic composite chains of responsibility on the client side. Make programming more flexible.
Definition: Avoids coupling between the sender and receiver of the request by giving multiple objects the opportunity to process the request. Connect the objects into a chain and pass the request along the chain until an object handles it. The process is actually a recursive call.
The main points are:
-
There are multiple objects working together on a task.
-
These objects use a chain storage structure, forming a chain where each object knows its next object.
-
An object handles a task, you can add some operations and pass the object to the next task. You can also end processing of the task on this object, and end the task.
-
The client is responsible for assembling the chain structure, but the client does not need to care who ultimately does the work.
Structure of the chain of responsibility pattern
The roles involved in the chain of responsibility mode are as follows:
-
Abstract Handler role: Defines an interface to handle requests. If necessary, the interface can define a method to set and return a reference to the next parent. This role is typically implemented by a Java abstract class or Java interface. The Handler class aggregation in the figure above gives a reference to a specific subclass’s next parent, and the abstract method handleRequest() specifies how subclasses handle requests.
-
The ConcreteHandler role: When a ConcreteHandler receives a request, it can choose to either process it or pass it on to the next provider. Because the concrete handler holds a reference to the next home, the concrete handler can access the next home if needed
Usage scenarios for the chain of responsibility pattern
-
If there are multiple objects can deal with the same request, but the concrete which is decided by the runtime dynamic object processing, this object can use cor pattern, the processing of the request object implementation into a job object, then construct the chain, when the request in the chain of transmission, depending on the running state of judgment.
-
Submit a request to one of multiple objects without specifying the request handler.
-
You need to dynamically specify a collection of objects to handle a request
Realization of responsibility chain pattern
Handler class, which defines an interface to handle requests
// Manager -Handler class, which defines an interface to handle requests
public abstract class Manager {
protected String name;
// Manager superior
protected Manager superior;
public Manager(String name) {
this.name = name;
}
// Set up the supervisor's superior -- the key method
public void setSuperior(Manager superior) {
this.superior = superior;
}
public abstract void requestApplications(Request request);
}
Copy the code
The concrete processing class handles the request for which it is responsible, and can access its successors, if it can handle it, otherwise the request goes to the successors
// The "manager" class can inherit the "manager" class by overriding the "request request" method
/ / the manager class
class CommonManager extends Manager {
public CommonManager(String name) {
super(name);
}
@Override
public void requestApplications(Request request) {
// The manager has the authority to approve a two-day leave of absence
if (request.requestType == "Leave" && request.number <= 2) {
System.out.println(name + ":" + request.requestContent + "The number" + request.number + "Approved");
} else {
// All other applications should be referred to the superior
if(superior ! =null) { superior.requestApplications(request); }}}}The "director" class also inherits the "manager" class
/ / director
class Majordomo extends Manager {
public Majordomo(String name) {
super(name);
}
@Override
public void requestApplications(Request request) {
// The director has the authority to approve a five-day leave
if (request.requestType == "Leave" && request.number <= 2) {
System.out.println(name + ":" + request.requestContent + "The number" + request.number + "Approved");
} else {
// All other applications should be referred to the superior
if(superior ! =null) { superior.requestApplications(request); }}}}// The "general manager" has the permission to process everything
/ / director
class GeneralManager extends Manager
{
public GeneralManager(String name) {
super(name);
}
@Override
public void requestApplications(Request request) {
// The general manager has the authority to approve any number of days of leave
if (request.requestType == "Leave") {
System.out.println(name + ":" + request.requestContent + "The number" + request.number + "Approved"); }}}Copy the code
Apply for class
/ / application
public class Request {
// Category of application
private String requestType;
// Application content
private String requestContent;
/ / the number of
private int number;
// The get/set method is omitted
}
Copy the code
Client code
public class Program {
// Client code
public static void main(String[] args) {
CommonManager jinli = new CommonManager("Zhang");
Majordomo zongjian = new Majordomo("Bill");
GeneralManager zongjinli = new GeneralManager("Fifty");
// Set the superior
jinli.setSuperior(zongjian);
zongjian.setSuperior(zongjinli);
Request request = new Request();
request.requestType = "Leave";
request.requestContent = Ask for leave "XX";
request.Number = 1; jinli.requestApplications(request); }}Copy the code
Advantages and disadvantages of the chain of responsibility model
Advantages:
The most important function of the responsibility chain pattern is: dynamic composition, decoupling of requestor and receiver.
Loose coupling of requester and receiver: Requester does not need to know the receiver and does not need to know how to process it. Each person is responsible for his or her own area of responsibility, leaving the rest to the successor. The components are completely decoupled.
Dynamic combination of responsibilities: The responsibility chain mode will disperse functions into separate responsibility objects, and then dynamically combine them to form a chain during use, so that the responsibility objects can be flexibly assigned, and the responsibilities of objects can be flexibly added and changed.
Disadvantages:
Generate a lot of fine-grained objects: Because function processing is scattered into separate responsibility objects, each object has a single function. To process the whole process, many responsibility objects are needed, resulting in a large number of fine-grained responsibility objects.
Not necessarily: Each responsibility object is only responsible for its own part, so that a request can come up and not be processed by the responsibility object even if the chain is completed. This requires providing default handling and being mindful of the effectiveness of the construction chain.
conclusion
There are two actions for a handler object in the chain of responsibility. The first is to process the request and the second is to pass the request to the next node. It is not allowed for a handler object to process the request and then pass the request to the previous node.
For a chain of responsibility, a request ultimately has only two possibilities. One is processed by a processing object, the other is not processed by all objects, for the former case we call the pure chain of responsibility mode, the latter is the impure chain of responsibility. In practice it is mostly impure chain of responsibility.