责任链模式是一种对象的行为模式。在责任链中有一个请求对象与多个处理对象,通过处理对象对其下家(下一处理对象)的引用而连接起来形成一条链。请求在这个链上传递。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任
使用场景
当某个业务流程由一系列细分的业务处理点组成,这些业务处理点的顺序需要支持动态组装,此时可考虑使用责任链模式;举个实际中的例子,比如参会需要经过一系列的流程:
process.png
而对于参会者来说,参会前并不关心自己具体要经过哪些流程,只需要按照安排接受校验即可
代码示例
根据上一章节的参会场景:
//会议
public class Conference {
private boolean shouldOrder;//该会议是否需要预约
public Conference(boolean shouldOrder) {
this.shouldOrder = shouldOrder;
}
public boolean isShouldOrder() {
return shouldOrder;
}
}
//会议请求
public class ConferenceRequest {
private Conference theConference;
private Object safeInfo;
private Object orderInfo;
public ConferenceRequest(Conference theConference) {
this.theConference = theConference;
}
public Conference getTheConference() {
return theConference;
}
}
//会议校验逻辑抽象类
public abstract class ConferenceReqCheckHandler {
protected ConferenceReqCheckHandler nextHandler;
public ConferenceReqCheckHandler setNextHandler(ConferenceReqCheckHandler nextHandler) {
this.nextHandler = nextHandler;
return this;
}
public void handle(ConferenceRequest request) {
if(this.nextHandler != null)
nextHandler.handle(request);
}
}
//会议安全校验
public class SafeCheckHandler extends ConferenceReqCheckHandler{
@Override
public void handle(ConferenceRequest request) {
System.out.println("安全校验开始");
if(!isSafe(request)) {
throw new SecurityException();
}
System.out.println("安全校验通过");
super.handle(request);
}
private boolean isSafe(ConferenceRequest request) {
//安全校验
return true;
}
}
//会议预约校验
public class OrderCheckHandler extends ConferenceReqCheckHandler{
@Override
public void handle(ConferenceRequest request) {
if(request.getTheConference().isShouldOrder()) {
System.out.println("该会议需要预约");
System.out.println("预约校验开始");
if(!hasOrdered(request)) {
throw new SecurityException();
}
System.out.println("预约校验通过");
} else {
System.out.println("该会议不需要预约");
}
super.handle(request);
}
private boolean hasOrdered(ConferenceRequest request) {
//预约校验
return true;
}
}
//会议是否有空位校验
public class AvailableCheckHandler extends ConferenceReqCheckHandler{
@Override
public void handle(ConferenceRequest request) {
System.out.println("检查该会议是否还有空位");
if(!isAvailable(request.getTheConference())) {
throw new SecurityException();
}
System.out.println("该会议还有空位,可参会");
super.handle(request);
}
private boolean isAvailable(Conference conference) {
//是否还有空位
return true;
}
}
上面代码示例中,可以针对每个校验点设置下一级校验点,每个校验点可以决定是否终止流程:
//客户端调用
public class Client {
public static void main(String[] args) {
Conference theConference = new Conference(true);
ConferenceRequest myConferenceRequest = new ConferenceRequest(theConference);
//安全校验 --> 预约校验 --> 是否有空位校验
ConferenceReqCheckHandler reqCheckHandler = new SafeCheckHandler()
.setNextHandler(new OrderCheckHandler().setNextHandler(new AvailableCheckHandler()));
reqCheckHandler.handle(myConferenceRequest);
}
}
//输出结果
安全校验开始
安全校验通过
该会议需要预约
预约校验开始
预约校验通过
检查该会议是否还有空位
该会议还有空位,可参会
当然也可以调整校验顺序(责任链顺序):
//客户端调用
public class Client {
public static void main(String[] args) {
Conference theConference = new Conference(true);
ConferenceRequest myConferenceRequest = new ConferenceRequest(theConference);
//安全校验 --> 是否有空位校验 --> 预约校验
ConferenceReqCheckHandler reqCheckHandler = new SafeCheckHandler()
.setNextHandler(new AvailableCheckHandler().setNextHandler(new OrderCheckHandler()));
reqCheckHandler.handle(myConferenceRequest);
}
}
//输出结果
安全校验开始
安全校验通过
检查该会议是否还有空位
该会议还有空位,可参会
该会议需要预约
预约校验开始
预约校验通过
责任链模式可以实现请求与处理之间的解耦,同时可以做到处理流程的动态可配;责任链模式在很多框架层都有应用,如Spring的安全校验,dubbo的处理拦截器等
应用实例
java.util.logging.Logger#log()
Apache Commons Chain
javax.servlet.Filter#doFilter()