2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
Chain of Responsibility Pattern: Avoid coupling the request sender and receiver together, give multiple objects the opportunity to receive requests, connect these objects into a chain, and pass the request along the chain until an object handles it. The Chain of Responsibility pattern is aObject Behavioral Pattern。
The core of the responsibility chain pattern structure is to introduce aAbstract Processor
As can be seen from the figure, the following two roles are included in the responsibility chain pattern structure diagram:
(1) Handler (abstract handler): It defines an interface for processing requests and is generally designed as an abstract class. Since different specific handlers process requests in different ways, an abstract request processing method is defined in it. Since each handler's downstream is also a handler, an abstract handler type object (successor in the structure diagram) is defined in the abstract handler as its successor to the downstream.ReferencesThrough this reference, handlers can be connected in a chain.
(2) ConcreteHandler: It is a subclass of the abstract handler and can handle user requests. The abstract request processing method defined in the abstract handler is implemented in the concrete handler class, and can access the next object in the chain to achieveRequest forwardingEffect.
In the chain of responsibility pattern, each object's reference to its next object is connected to form a chain. The request is passed along the chain until an object in the chain finally handles the request, which allows the system to dynamically reorganize the chain and assign responsibilities without affecting the client.
The core of the responsibility chain pattern lies in the design of the abstract handler class. The typical code of the abstract handler class is as follows:
abstract class Handler {
//维持对下家的引用
protected Handler successor;
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract void handleRequest(String request);
}
In the above code, the abstract handler defines a reference object to the next client so that the request can be forwarded to the next client. The accessor of this object can be set to protected so that it can be used in its subclasses.
The concrete handler is a subclass of the abstract handler, which has two major functions:
The typical code of the specific handler class is as follows:
class ConcreteHandler extends Handler {
public void handleRequest(String request) {
if (请求满足条件) {
//处理请求
}
else {
this.successor.handleRequest(request); //转发请求
}
}
}
A purchase order approval system is implemented in a hierarchical manner, that is, different levels of supervisors will approve the purchase order according to the different purchase amounts.
The director can approve purchase orders below 50,000 yuan, the vice chairman can approve purchase orders between [50,000 and 100,000 yuan], and the chairman can approve purchase orders between [100,000 and 500,000 yuan]. Purchase orders of 500,000 yuan or more require a board meeting for discussion and decision.
Since each approver of a position has a subordinate (except the board of directors), and their behaviors are common, all involving forwarding the approval to the successor. Therefore, an approver class is designed as an abstract handler:
//审批者类: 抽象处理者
abstract class Approver {
protected Approver successor; //定义后继对象
protected String name; //审批者姓名
public Approver(String name) {
this.name = name;
}
//设置后继者
public void setSuccessor(Approver successor) {
this.successor = successor;
}
public abstract void processRequest(PurchaseRequest request);
}
Then, as specific handlers of each position, we need to implement the abstract handler:
//主任: 具体处理者
class Director extends Approver{
public Director(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 50000) {
System.out.println(
MessageFormat.format("主任 {0} 审批采购单:{1}, 金额:{2}元, 采购目的:{3}。",
this.name, request.getNumber(), request.getAmount(), request.getPurpose())
);
} else {
this.successor.processRequest(request); //转发请求
}
}
}
//副董事长:具体处理类
class VicePresident extends Approver{
public VicePresident(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 100000) {
System.out.println(
MessageFormat.format("副董事长 {0} 审批采购单:{1}, 金额:{2}元, 采购目的:{3}。",
this.name, request.getNumber(), request.getAmount(), request.getPurpose())
);
} else {
this.successor.processRequest(request);
}
}
}
//董事长类:具体处理者
class President extends Approver{
public President(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
if (request.getAmount() < 500000) {
System.out.println(
MessageFormat.format("董事长 {0} 审批采购单:{1}, 金额:{2}元, 采购目的:{3}。",
this.name, request.getNumber(), request.getAmount(), request.getPurpose())
);
} else {
this.successor.processRequest(request);
}
}
}
//董事会类:具体处理者
class Congress extends Approver{
public Congress(String name) {
super(name);
}
@Override
public void processRequest(PurchaseRequest request) {
System.out.println(
MessageFormat.format("召开董事会 审批采购单:{0}, 金额:{1}元, 采购目的:{2}。",
request.getNumber(), request.getAmount(), request.getPurpose())
);
}
}
Define another purchase order class as the target that needs to be approved:
//采购单: 请求类
class PurchaseRequest {
private double amount; //采购金额
private int number; //采购单编号
private String purpose; //采购目的
public PurchaseRequest(double amount, int number, String purpose) {
this.amount = amount;
this.number = number;
this.purpose = purpose;
}
public double getAmount() {
return amount;
}
public void setAmount(double amount) {
this.amount = amount;
}
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getPurpose() {
return purpose;
}
public void setPurpose(String purpose) {
this.purpose = purpose;
}
}
Write client test code:
class Client {
public static void main(String[] args) {
Approver kangXi, yongZheng, qianLong, hanLinYuan;
kangXi = new Director("康熙");
yongZheng = new VicePresident("雍正");
qianLong = new VicePresident("乾隆");
hanLinYuan = new Congress("翰林院");
//创建职责链
kangXi.setSuccessor(yongZheng);
yongZheng.setSuccessor(qianLong);
qianLong.setSuccessor(hanLinYuan);
//创建采购单
PurchaseRequest pr1 = new PurchaseRequest(45000, 10001, "购买刀");
kangXi.processRequest(pr1);
PurchaseRequest pr2 = new PurchaseRequest(60000, 10002, "购买枪");
kangXi.processRequest(pr2);
PurchaseRequest pr3 = new PurchaseRequest(160000, 10003, "购买火炮");
kangXi.processRequest(pr3);
PurchaseRequest pr4 = new PurchaseRequest(800000, 10004, "购买军舰");
kangXi.processRequest(pr4);
}
}
Compile and run the program. The output is as follows:
主任 康熙 审批采购单:10,001, 金额:45,000元, 采购目的:购买刀。
副董事长 雍正 审批采购单:10,002, 金额:60,000元, 采购目的:购买枪。
董事长 乾隆 审批采购单:10,003, 金额:160,000元, 采购目的:购买火炮。
召开董事会 审批采购单:10,004, 金额:800,000元, 采购目的:购买军舰。
Let's design a case that is slightly different from the above, which can expand our understanding of the responsibility chain pattern and the scenarios in which it can be applied.
The school will assign some tasks to the class for processing, these types include one, two, three, four and so on. The class teacher can handle the three types of tasks, one, two, three, the monitor can handle the two types of tasks, one, two, and the study committee member can handle the task of one. When the class teacher receives a task, he will first hand it over to the class monitor. If the next person can't handle it, the class teacher will handle it himself; when the class monitor receives a task, he will first hand it over to the study committee member. If the next person can't handle it, the class monitor will handle it himself; when the study committee member receives a task, if he can handle it himself. And when they can't handle it, they will give feedback to the upper level.
The following Handler class is designed as an abstract handler:
Since you and your downstream customers may not be able to handle certain class tasks, there may be feedback upward, so the request method of the processor needs to have a boolean return value to tell the upstream customer whether the task can be handled.
abstract class Handler {
protected Handler successor; //定义后继对象
public void setSuccessor(Handler successor) {
this.successor = successor;
}
public abstract boolean handleRequest(String taskName);
}
Below, the class teacher, class monitor, and study committee member are designed as specific handlers.
By default, the class teacher will first assign the task to the monitor, and the monitor will first assign the task to the study committee member. The study committee member can only handle one type of task, and if it cannot be handled, false will be returned.
If the feedback received by the monitor is false, he will handle it himself. He can only handle one or two type tasks. If he cannot handle it, he will return false.
If the class teacher receives false feedback, he will handle it himself. He can only handle one, two, and three types of tasks. If he cannot handle it, he will return false.
//班主任
class HeadTeacher extends Handler{
@Override
public boolean handleRequest(String taskName) {
boolean handled = successor.handleRequest(taskName);
if (handled) {
return true;
}
if (taskName.equals("one") || taskName.equals("two") || taskName.equals("three")) {
System.out.println("班主任处理了该事务");
return true;
}
return false;
}
}
//班长
class Monitor extends Handler{
@Override
public boolean handleRequest(String taskName) {
boolean handled = successor.handleRequest(taskName);
if (handled) {
return true;
}
if (taskName.equals("one") || taskName.equals("two")) {
System.out.println("班长处理了该事务");
return true;
}
return false;
}
}
//学习委员
class StudyCommissary extends Handler{
@Override
public boolean handleRequest(String taskName) {
boolean handled;
if (successor == null) { //注意学习委员可能没有下家,所以这里判一下是否为空
handled = false;
} else {
handled = successor.handleRequest(taskName);
}
if (handled) {
return true;
}
if (taskName.equals("one")) {
System.out.println("学习委员处理了该事务");
return true;
}
return false;
}
}
Write client test code:
Set a subordinate for each position, but note that the study committee member has no subordinate.
Also, if there is a task that the head teacher cannot handle, a line of log will be printed to explain it.
public class SchoolClient {
public static void main(String[] args) {
Handler headTeacher, monitor, studyCommissary;
headTeacher = new HeadTeacher();
monitor = new Monitor();
studyCommissary = new StudyCommissary();
headTeacher.setSuccessor(monitor);
monitor.setSuccessor(studyCommissary);
studyCommissary.setSuccessor(null); //没有下一职责人
startRequest(headTeacher, "one");
startRequest(headTeacher, "two");
startRequest(headTeacher, "three");
startRequest(headTeacher, "four");
}
private static void startRequest(Handler headTeacher, String taskName) {
if (! headTeacher.handleRequest(taskName)) {
System.out.println("该班级处理不了此类任务!");
}
}
}
Compile and run the program. The output is as follows:
学习委员处理了该事务
班长处理了该事务
班主任处理了该事务
该班级处理不了此类任务!
The chain of responsibility model can be considered in the following situations:
Reference books:
The Art of Design Patterns——Liu Wei