简介
责任链模式(Chain of Responsibility Pattern)将链中每一个节点都看作一个对象,每个节点处理的请求均不同,且内部自动维护下一个节点对象。当一个请求从链式的首端发出时,会沿着责任链预设的路径依次传递到每一个节点对象,直至被链中的某个对象处理为止,属于行为型设计模式。
通用模板
-
创建抽象处理者:定义一个请求处理的方法,并维护一个下一处理节点Handler对象的引用。
// 抽象处理者 public abstract class Handler { protected Handler nextHandler; public void setNextHandler(Handler nextHandler) { this.nextHandler = nextHandler; } public abstract void handleRequest(String request); }
-
创建具体处理者:对请求进行处理,如果不感兴趣,则进行转发。
// 具体处理者A public class ConcreteHandlerA extends Handler { @Override public void handleRequest(String request) { if ("requestA".equals(request)) { System.out.println(this.getClass().getSimpleName() + " deal with request:" + request); return; } if (this.nextHandler != null){ this.nextHandler.handleRequest(request); } } }
// 具体处理者B public class ConcreteHandlerB extends Handler { @Override public void handleRequest(String request) { if ("requestB".equals(request)) { System.out.println(this.getClass().getSimpleName() + " deal with request:" + request); return; } if (this.nextHandler != null){ this.nextHandler.handleRequest(request); } } }
说明: 在上面代码中,我们把消息硬编码为String类型,而在真实业务中,消息是具备多样性的,可以是int、String或者自定义类型。因此,在上面代码的基础上,可以对消息类型进行抽象Request,增强了消息的兼容性。
模板测试
-
测试代码
public class Client { public static void main(String[] args) { Handler handlerA = new ConcreteHandlerA(); Handler handlerB = new ConcreteHandlerB(); // 设置责任链 handlerA.setNextHandler(handlerB); // 创建请求:我们把消息硬编码为String类型,而在真实业务中, // 消息是具备多样性的,可以是int、String或者自定义类型。 // 因此,在上面代码的基础上,可以对消息类型进行抽象Request,增强了消息的兼容性。 String request = "requestB"; // 发送请求 handlerA.handleRequest(request); } }
-
测试结果
ConcreteHandlerB deal with request:requestB
应用场景
在日常生活中,责任链模式是比较常见的。我们平时处理工作中的一些事务,往往是各部门协同合作来完成某一个任务的。而每个部门都有各自的职责,因此,很多时候事情完成一半,便会转交到下一个部门,直到所有部门都审批通过,事情才能完成。还有我们平时说的“过五关,斩六将”其实就是闯关,也是责任链模式的一种应用场景。
责任链模式主要解耦了请求与处理,客户只需将请求发送到链上即可,不需要关心请求的具体内容和处理细节,请求会自动进行传递,直至有节点对象进行处理。责任链模式主要适用于以下应用场景。 (1)多个对象可以处理同一请求,但具体由哪个对象处理则在运行时动态决定。
(2)在不明确指定接收者的情况下,向多个对象中的一个提交请求。
(3)可动态指定一组对象处理请求。
优点
(1)将请求与处理解耦。
(2)请求处理者(节点对象)只需关注自己感兴趣的请求进行处理即可,对于不感兴趣的请求,直接转发给下一个节点对象。
(3)具备链式传递处理请求功能,请求发送者不需要知晓链路结构,只需等待请求处理结果即可。 (4)链路结构灵活,可以通过改变链路结构动态地新增或删减责任。
(5)易于扩展新的请求处理类(节点),符合开闭原则。
缺点
(1)责任链太长或者处理时间过长,会影响整体性能。
(2)如果节点对象存在循环引用,则会造成死循环,导致系统崩溃。
“生搬硬套”实战
场景描述
我们将使用责任链模式来处理员工请假申请的例子。在这个例子中,我们有三种类型的请假请求:病假、事假和年假。每个请求将根据请假天数和类型被不同的经理审批。
代码开发
-
实战中我们用自定义类来代替模板中的字符串,先自定义一个请假请求类:
// 请假请求类 public class LeaveRequest { private String type; private int days; public LeaveRequest(String type, int days) { this.type = type; this.days = days; } public String getType() { return type; } public int getDays() { return days; } }
-
创建抽象处理者(这里指请假请求的handler)
// 请假请求处理者 public abstract class LeaveRequestHandler { protected LeaveRequestHandler nextHandler; public LeaveRequestHandler setNext(LeaveRequestHandler handler) { this.nextHandler = handler; return handler; } public abstract void handleRequest(LeaveRequest request); }
-
创建具体处理者(这里指病假处理者、事假处理者以及年假处理者)
// 病假处理者 public class SickLeaveHandler extends LeaveRequestHandler { @Override public void handleRequest(LeaveRequest request) { if ("Sick".equals(request.getType())) { System.out.println("Sick leave request is handled by " + getClass().getSimpleName()); } else { if (nextHandler != null) { nextHandler.handleRequest(request); } } } }
// 事假处理者 public class PersonalLeaveHandler extends LeaveRequestHandler { @Override public void handleRequest(LeaveRequest request) { if ("Personal".equals(request.getType()) && request.getDays() <= 5) { System.out.println("Personal leave request is handled by " + getClass().getSimpleName()); } else { if (nextHandler != null) { nextHandler.handleRequest(request); } } } }
// 年假处理者 public class AnnualLeaveHandler extends LeaveRequestHandler { @Override public void handleRequest(LeaveRequest request) { if ("Annual".equals(request.getType())) { System.out.println("Annual leave request is handled by " + getClass().getSimpleName()); } else { if (nextHandler != null) { nextHandler.handleRequest(request); } } } }
至此,我们就通过“生搬硬套”责任链模式的模板设计出一套请假申请的案例,接下来我们进行测试:
-
测试代码
public class Client { public static void main(String[] args) { LeaveRequestHandler sickHandler = new SickLeaveHandler(); LeaveRequestHandler personalHandler = new PersonalLeaveHandler(); LeaveRequestHandler annualHandler = new AnnualLeaveHandler(); // 设置责任链 sickHandler.setNext(personalHandler).setNext(annualHandler); // 创建请假请求 LeaveRequest sickLeave = new LeaveRequest("Sick", 3); LeaveRequest personalLeave = new LeaveRequest("Personal", 4); LeaveRequest annualLeave = new LeaveRequest("Annual", 7); // 发送请求 sickHandler.handleRequest(sickLeave); sickHandler.handleRequest(personalLeave); sickHandler.handleRequest(annualLeave); } }
-
测试结果
Sick leave request is handled by SickLeaveHandler Personal leave request is handled by PersonalLeaveHandler Annual leave request is handled by AnnualLeaveHandler
总结
责任链模式(Chain of Responsibility)是一种处理请求的模式,它让多个处理器都有机会处理该请求,直到其中某个处理成功为止。责任链模式把多个处理器串成链,然后让请求在链上传递: