责任链模式(ChainOfResponsibility)
亦称:职责链模式、命令链、CoR、Chain of Command、Chain of Responsibility
责任链是一种行为设计模式,允许你将请求沿着处理者链进行发送。收到请求后,每个处理者均可对请求进行处理,或将其传递给链上的下个处理者。
责任链是由很多责任节点串联起来的一条任务链条,其中每一个责任节点都是一个业务处理环节。责任链模式(Chain ofResponsibility)允许业务请求者将责任链视为一个整体并对其发起请求,而不必关心链条内部具体的业务逻辑与流程走向,也就是说,请求者不必关心具体是哪个节点起了作用,总之业务最终能得到相应的处理。在软件系统中,当一个业务需要经历一系列业务对象去处理时,我们可以把这些业务对象串联起来成为一条业务责任链,请求者可以直接通过访问业务责任链来完成业务的处理,最终实现请求者与响应者的解耦。
现实场景
- 简单的生产线
倘若一个系统中有一系列零散的功能节点,它们都负责处理相关的业务,但处理方式又各不相同。这时客户面对这么一大堆功能节点可能无从下手,根本不知道选择哪个功能节点去提交请求,返回的结果也许只是个半成品,还得再次提交给下一个功能节点,处理过程相当烦琐。虽然从某种角度看,每个功能节点均承担各自的义务,分工明确、各司其职,但从外部来看则显得毫无组织,团队犹如一盘散沙。所以为了更高效、更完整地解决客户的问题,各节点一定要发扬团队精神,利用责任链模式组织起来,形成一个有序、有效的业务处理集群,为客户提供更方便、更快捷的服务。
以最简单的责任链举例,汽车生产线的制造流程就使用了这种模式。首先我们进行劳动分工,将汽车零件的安装工作拆分并分配给各安装节点,责任明确划分;然后架构生产线,将安装节点组织起来,首尾相接,规划操作流程;最终,通过生产线的传递,汽车便从零件到成品得以量产,生产效率大大提升。
java
// 定义一个处理请求的接口
interface Handler {
void setNextHandler(Handler handler);
void handleRequest(Request request);
}
// 具体的处理器类1
class ConcreteHandler1 implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
nextHandler = handler;
}
@Override
public void handleRequest(Request request) {
if (request.getType().equals("Type1")) {
System.out.println("ConcreteHandler1处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 具体的处理器类2
class ConcreteHandler2 implements Handler {
private Handler nextHandler;
@Override
public void setNextHandler(Handler handler) {
nextHandler = handler;
}
@Override
public void handleRequest(Request request) {
if (request.getType().equals("Type2")) {
System.out.println("ConcreteHandler2处理了请求:" + request.getContent());
} else if (nextHandler != null) {
nextHandler.handleRequest(request);
}
}
}
// 请求类
class Request {
private String type;
private String content;
public Request(String type, String content) {
this.type = type;
this.content = content;
}
public String getType() {
return type;
}
public String getContent() {
return content;
}
}
// 客户端代码
public class Main {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNextHandler(handler2);
Request request1 = new Request("Type1", "Request Content 1");
Request request2 = new Request("Type2", "Request Content 2");
Request request3 = new Request("Type3", "Request Content 3");
handler1.handleRequest(request1);
handler1.handleRequest(request2);
handler1.handleRequest(request3);
}
}
在上面的例子中,我们定义了一个Handler
接口,该接口具有设置下一个处理器和处理请求的方法。然后我们创建了两个具体的处理器类ConcreteHandler1
和ConcreteHandler2
,分别处理请求的类型Type1
和Type2
。如果请求的类型不是当前处理器所能处理的,就将请求传递给下一个处理器处理。
最后,在客户端代码中,我们创建了两个处理器实例,并通过setNextHandler
方法将它们串联起来形成责任链。然后我们创建了三个不同类型的请求,并通过调用handleRequest
方法将其交给责任链进行处理。
在执行的过程中,当请求的类型匹配到对应的处理器时,该处理器就会处理该请求,否则会将该请求传递给下一个处理器。这样,请求就会依次经过责任链中的处理器进行处理。
例如在mybatius中的缓存设计使用了装饰器+责任链,通过log缓存、序列化缓存、同步缓存等一系列缓存支持缓存的多种功能,优缺点是,
- 你可以控制请求处理的顺序。
- 单一职责原则。你可对发起操作和执行操作的类进行解耦。
- 开闭原则。你可以在不更改现有代码的情况下在程序中新增处理者。
- 缺点:部分请求可能未被处理。
- 缺点:debug可能会比较困难。
在sql解析中也有用到责任链,mybatius将sql解析成sqlNode,然后通过责任链,调用每个sqlNode的解析方式(解析类)。将所有解析完成的sql拼接成统一的sql,再利用jdbc,创建connection,利用 preparedstatement将参数设置到sql中,获取resultset