设计模式之职责链模式
定义
使每个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,
直到有一个对象处理它为止。如公司员工请假,可以批假的领导有部门负责人、副总经理、总经理等,但每个领导可以批准的天数不同,
员工只需要提交申请,不需要知道最终由谁批准。
结构
- Handler,抽象处理者,定义处理请求的接口,内部持有一个后继者对象。
- ConcreteHandler,具体处理者,判断自己能否处理,不能则交给后继者处理。
- Client,客户端,创建处理链并发送请求。
简单实现
抽象处理者
public abstract class Handler {
/**
* 后继者
*/
private Handler successor;
public void setSuccessor(
Handler successor) {
this.successor = successor;
}
public Handler getSuccessor() {
return successor;
}
abstract void handleRequest(String context);
}
具体处理者
public class ConcreteHandler1 extends Handler {
@Override
void handleRequest(String context) {
if (context.startsWith("one")) {
System.out.println("ConcreteHandler1 handleRequest()");
} else {
if (getSuccessor() != null) {
getSuccessor().handleRequest(context);
}
}
}
}
另一个处理者
public class ConcreteHandler2 extends Handler {
@Override
void handleRequest(String context) {
if (context.startsWith("two")) {
System.out.println("ConcreteHandler2 handleRequest()");
} else {
if (getSuccessor() != null) {
getSuccessor().handleRequest(context);
}
}
}
}
客户端
public class Client {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setSuccessor(handler2);
handler1.handleRequest("one");
System.out.println("=============");
handler1.handleRequest("two");
}
}
请假流程
以一个具体的业务场景请假为例
抽象处理者
public abstract class Handler {
/**
* 后继者
*/
private Handler successor;
public void setSuccessor(
Handler successor) {
this.successor = successor;
}
public Handler getSuccessor() {
return successor;
}
abstract void handleRequest(String username, int days);
}
定义处理方法,哪个员工请多少天。
具体处理者
定义三个领导,每个领导可以批准的请假天数不同
/**
* 部门负责人只能批准3天请假天数
*/
public class DepartmentManager extends Handler {
@Override
void handleRequest(String username, int days) {
if (days <= 3) {
System.out.println("部门负责人批准" + username + "请假" + days + "天");
} else {
if (getSuccessor() != null) {
getSuccessor().handleRequest(username, days);
}
}
}
}
/**
* 副总经理只能批准5天请假天数
*/
public class ViceGeneralManager extends Handler {
@Override
void handleRequest(String username, int days) {
if (days <= 5) {
System.out.println("副总经理批准" + username + "请假" + days + "天");
} else {
if (getSuccessor() != null) {
getSuccessor().handleRequest(username, days);
}
}
}
}
/**
* 总经理只能批准10天请假天数
*/
public class GeneralManager extends Handler {
@Override
void handleRequest(String username, int days) {
if (days <= 10) {
System.out.println("总经理批准" + username + "请假" + days + "天");
} else {
if (getSuccessor() != null) {
getSuccessor().handleRequest(username, days);
}
}
}
}
客户端
public class Client {
public static void main(String[] args) {
Handler handler1 = new DepartmentManager();
Handler handler2 = new ViceGeneralManager();
Handler handler3 = new GeneralManager();
handler1.setSuccessor(handler2);
handler2.setSuccessor(handler3);
handler1.handleRequest("小明", 2);
handler1.handleRequest("小明", 4);
handler1.handleRequest("小明", 6);
}
}
输出结果为
部门负责人批准小明请假2天
副总经理批准小明请假4天
总经理批准小明请假6天
功能链
功能链是职责链的一种变形
- 职责链:一个请求在链中传递,只要有一个对象处理了,就会停止
- 功能链:一个请求在链中传递,每个处理者负责某一方面的功能,处理完之后继续向下传递
职责链模式在Tomcat和SpringMVC中的实现
Tomcat中的实现
Tomcat中的FilterChain
/**
* Implementation of <code>javax.servlet.FilterChain</code> used to manage
* the execution of a set of filters for a particular request. When the
* set of defined filters has all been executed, the next call to
* <code>doFilter()</code> will execute the servlet's <code>service()</code>
* method itself.
*
* @author Craig R. McClanahan
*/
public final class ApplicationFilterChain implements FilterChain {
@Override
public void doFilter(ServletRequest request, ServletResponse response)
throws IOException, ServletException {
internalDoFilter(request,response);
}
private void internalDoFilter(ServletRequest request,
ServletResponse response)
throws IOException, ServletException {
// Call the next filter if there is one
if (pos < n) {
ApplicationFilterConfig filterConfig = filters[pos++];
try {
Filter filter = filterConfig.getFilter();
filter.doFilter(request, response, this);
} catch (IOException | ServletException | RuntimeException e) {
throw e;
} catch (Throwable e) {
e = ExceptionUtils.unwrapInvocationTargetException(e);
ExceptionUtils.handleThrowable(e);
throw new ServletException(sm.getString("filterChain.filter"), e);
}
return;
}
servlet.service(request, response);
}
}
一个过滤器链FilterChain就是一个功能链,每个过滤器负责自己的处理,然后传递给下一个过滤器,最后交给Servlet来处理。
SpringMVC中的实现
SpringMVC中的HandlerExecutionChain
/**
* Handler execution chain, consisting of handler object and any handler interceptors.
* Returned by HandlerMapping's {@link HandlerMapping#getHandler} method.
*
* @author Juergen Hoeller
* @since 20.06.2003
* @see HandlerInterceptor
*/
public class HandlerExecutionChain {
private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);
private final Object handler;
@Nullable
private HandlerInterceptor[] interceptors;
@Nullable
private List<HandlerInterceptor> interceptorList;
private int interceptorIndex = -1;
/**
* Apply preHandle methods of registered interceptors.
* @return {@code true} if the execution chain should proceed with the
* next interceptor or the handler itself. Else, DispatcherServlet assumes
* that this interceptor has already dealt with the response itself.
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
HandlerInterceptor[] interceptors = getInterceptors();
if (!ObjectUtils.isEmpty(interceptors)) {
for (int i = 0; i < interceptors.length; i++) {
HandlerInterceptor interceptor = interceptors[i];
if (!interceptor.preHandle(request, response, this.handler)) {
triggerAfterCompletion(request, response, null);
return false;
}
this.interceptorIndex = i;
}
}
return true;
}
}
和过滤器链类似,拦截器链HandlerExecutionChain也是一个功能链,执行完所有的拦截器才能执行最终的业务处理方法。
总结
优点
- 请求者和处理者解耦,请求者不需要知道最终由哪个对象来处理该请求。
- 很容易增加新的处理者,不需要修改原有的结构和代码。
缺点
- 由于一个请求没有一个明确的处理者,无法保证一定被处理。
- 建立链不当可能造成循环调用,导致系统进入死循环。
本质
职责链模式的本质是分离职责,动态组合。分离职责是前提,只有先将复杂的功能分离开,才能合理的规划和定义职责类。
使用场景
- 有多个对象可以处理同一个请求,但具体由哪个对象来处理是在运行时动态确定的。
- 想要动态地指定处理一个请求的对象集合
参考
大战设计模式【18】—— 职责链模式
设计模式(二十四)——职责链模式(SpringMVC源码分析)
设计模式的征途—14.职责链(Chain of Responsibility)模式
责任链模式(职责链模式)详解
研磨设计模式-书籍