设计模式之行为型模式中的责任链模式(Chain of Responsibility Pattern)

责任链模式

一、基本介绍

责任链(Chain of Responsibility)模式,也叫职责链模式,属于行为型模式。该模式为请求创建了一个接收者对象的链,通常链中每个接收者都包含对另一个接收者的引用。当请求发生时,请求沿着这条链发送传递,链中的接收者接收到请求之后,可根据自己的职责,处理请求中相应的业务,处理完成后并将请求传递给链上的下一个接收者,直到这条链走完处理掉所有的业务为止。

二、责任链模式的实现

2.1、职责链模式中的主要角色及职责

职责链模式主要包含以下角色

  • 抽象处理者(Handler)角色:该角色一般是一个抽象类,类中声明了所有处理者用于请求处理的通用接口,以及指向下一个处理者的引用。
  • 具体处理者(Concrete Handler)角色:该角色是一般是抽象处理者(抽象类)的子类,它实现了抽象处理者的处理方法,包含了实际的请求处理代码,用于处理请求中它自己负责的业务,并可以访问它的后继处理者。如果可以处理当前请求,则处理,否则就将该请求交给后继者去处理,从而形成一个职责链。
  • 客户端(Client)角色:创建责任链,并向链上的任意一个处理者对象提交请求,它不关心处理细节和请求的传递过程。

2.2、责任链模式结构

三、责任链模式的应用

3.1、责任链模式解决问题案例

🌰 模拟某公司请假审批流程模块,流程如下:

graph LR
    S((开始))
    A(申请人)
    B(主任)
    C(部门经理)
    D(人力资源部经理)
    E(主管领导)
    F(申请人查阅)
    G(知会考勤管理员)
    P((结束))

    S --> A --普通员工--> B --> C
    subgraph 请假天数大于3时需要人力资源部经理和主管领导额外审批
    C --请假天数<=3--> F
    C --请假天数>3--> D --> E --> F
    end
    F --> G --> P

3.1.1、定义抽象处理者(Handler)角色

LeaderHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
/**
* @author : sunys
* @version : v1.0
* @createTime : 2021/1/16 20:08
* @description : 抽象领导处理者
*/
public abstract class LeaderHandler {
private LeaderHandler nextLeader;
protected String name;

public LeaderHandler(String name) {
this.name = name;
}

public LeaderHandler getNextLeader() {
return nextLeader;
}

public void setNextLeader(LeaderHandler nextLeader) {
this.nextLeader = nextLeader;
}

/**
* 抽象审批处理方法
*
* @param days 请假天数
*/
public abstract void approval(Integer days);
}

3.1.2、定义具体处理者(Concrete Handler)角色

DirectorHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @author : sunys
* @version : v1.0
* @createTime : 2021/1/16 20:18
* @description : 主任具体处理者
*/
public class DirectorHandler extends LeaderHandler {
public DirectorHandler(String name) {
super(name);
}

@Override
public void approval(Integer days) {
System.out.println("--->请假" + days + "天,由" + this.name + "审批通过--->");
LeaderHandler nextLeader = super.getNextLeader();
if (null != nextLeader) {
nextLeader.approval(days);
}
}
}
DepartmentManagerHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* @author : sunys
* @version : v1.0
* @createTime : 2021/1/16 20:29
* @description : 部门经理具体处理者
*/
public class DepartmentManagerHandler extends LeaderHandler {
public DepartmentManagerHandler(String name) {
super(name);
}

@Override
public void approval(Integer days) {
System.out.println("--->请假" + days + "天,由" + this.name + "审批通过--->");
LeaderHandler nextLeader = super.getNextLeader();
if (null != nextLeader) {
nextLeader.approval(days);
}
}
}
ResourcesManagerHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author : sunys
* @version : v1.0
* @createTime : 2021/1/16 20:30
* @description : 人力资源部经理具体处理者
*/
public class ResourcesManagerHandler extends LeaderHandler {
public ResourcesManagerHandler(String name) {
super(name);
}

@Override
public void approval(Integer days) {
if (days > 3) {
System.out.println("--->请假" + days + "天,超过3天,由" + this.name + "审批通过--->");
}
LeaderHandler nextLeader = super.getNextLeader();
if (null != nextLeader) {
nextLeader.approval(days);
}
}
}
CompetentLeaderHandler
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
* @author : sunys
* @version : v1.0
* @createTime : 2021/1/16 20:39
* @description :
*/
public class CompetentLeaderHandler extends LeaderHandler {
public CompetentLeaderHandler(String name) {
super(name);
}

@Override
public void approval(Integer days) {
if (days > 3) {
System.out.println("--->请假" + days + "天,超过3天,由" + this.name + "审批通过--->");
}
LeaderHandler nextLeader = super.getNextLeader();
if (null != nextLeader) {
nextLeader.approval(days);
}
}
}

3.1.3、定义客户端(Client)角色

Client
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
/**
* @author : sunys
* @version : v1.0
* @createTime : 2021/1/16 20:05
* @description :
*/
public class Client {

public static void approvalTest(Integer days) {
//组装责任链
DirectorHandler directorHandler = new DirectorHandler("部门侯主任");
DepartmentManagerHandler departmentManagerHandler = new DepartmentManagerHandler("部门吴经理");
ResourcesManagerHandler resourcesManagerHandler = new ResourcesManagerHandler("人力资源王经理");
CompetentLeaderHandler competentLeaderHandler = new CompetentLeaderHandler("主管领导老王");

directorHandler.setNextLeader(departmentManagerHandler);
departmentManagerHandler.setNextLeader(resourcesManagerHandler);
resourcesManagerHandler.setNextLeader(competentLeaderHandler);
//提交请求
directorHandler.approval(days);
System.out.println("流程审批结束");
}
}

3.1.4、单元测试

ClientTest
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
* The type Client test.
*/
class ClientTest {

/**
* Client test.
*/
@Test
void clientTest() {
System.out.println("Client call director");
System.out.println("====================================");
//请假小于3天
Client.approvalTest(2);
System.out.println("====================================");
//请假大于3天
Client.approvalTest(5);
System.out.println("====================================");
}
}

测试结果:
单元测试结果

3.2、责任链模式的应用

责任链模式在框架的开发中使用及其广泛,比如过滤器(Interceptor)和拦截器(Interceptor),比如Spring Interceptor和Servlet Filter

3.2.1、 Filter 和 Interceptor

责任链模式在框架的开发中使用及其广泛,比如Spring Interceptor拦截器和Servlet Filter过滤器。
Filter
Filter抽象处理者角色,ApplicationFilterChain、VirtualFilterChain等是责任链模式的具体实现类。

FilterChain
1
2
3
public interface FilterChain {
void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}
ApplicationFilterChain
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public final class ApplicationFilterChain implements FilterChain {
...//源码省略

public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
if (Globals.IS_SECURITY_ENABLED) {
ServletRequest req = request;
ServletResponse res = response;

try {
AccessController.doPrivileged(() -> {
this.internalDoFilter(req, res);
return null;
});
} catch (PrivilegedActionException var7) {
Exception e = var7.getException();
if (e instanceof ServletException) {
throw (ServletException)e;
}

if (e instanceof IOException) {
throw (IOException)e;
}

if (e instanceof RuntimeException) {
throw (RuntimeException)e;
}

throw new ServletException(e.getMessage(), e);
}
} else {
this.internalDoFilter(request, response);
}

}
...//源码省略
}

Filter
HandlerInterceptor抽象处理者角色,LocaleChangeInterceptor等是责任链模式的具体实现类。

HandlerInterceptor
1
2
3
4
5
6
7
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3) throws Exception;

void postHandle(HttpServletRequest var1, HttpServletResponse var2, Object var3, ModelAndView var4) throws Exception;

void afterCompletion(HttpServletRequest var1, HttpServletResponse var2, Object var3, Exception var4) throws Exception;
}
LocaleChangeInterceptor
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class LocaleChangeInterceptor extends HandlerInterceptorAdapter {
...//源码省略

public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws ServletException {
String newLocale = request.getParameter(this.getParamName());
if (newLocale != null && this.checkHttpMethod(request.getMethod())) {
LocaleResolver localeResolver = RequestContextUtils.getLocaleResolver(request);
if (localeResolver == null) {
throw new IllegalStateException("No LocaleResolver found: not in a DispatcherServlet request?");
}

try {
localeResolver.setLocale(request, response, this.parseLocaleValue(newLocale));
} catch (IllegalArgumentException var7) {
if (!this.isIgnoreInvalidLocale()) {
throw var7;
}

this.logger.debug("Ignoring invalid locale value [" + newLocale + "]: " + var7.getMessage());
}
}

return true;
}

...//源码省略
}

3.2.1、 Activiti工作流

Activit整体上采用命令模式,同时搭配其对应的责任链来完成,它的各操作方法其底层基本都是以命令模式来实现,从而实现代码功能解耦,将流程引擎大部分涉及到客户端的需求业务交给外部以具体命令实现类的实现。

  • Command命令接口,所有的具体命令都需要实现该类,最终业务就是执行该类的execute方法。
  • CommandContext命令上下文,为具体命令的执行提供上下文支撑。

四、总结

这种模式的特点:

  • 这种模式下,将请求的发送者和接收者进行了完美的解耦,调用着无须关心请求的传递过程和请求的处理细节。
  • 增强了系统的可扩展性,可以根据需要增加或减少请求处理类,满足设计原则中的开闭原则 (Open Close Principle)
  • 这种模式下,每个接收者只需要处理自己负责的业务,不用处理的传递给下一个接受者完成,各个接收者责任范围分工明确,符合类的单一职责原则 (Single Responsibility Principle)
  • 使用这种模式,特别是在链比较长的时候,性能会受到影响,因此需要尽可能控制链中最大节点数量,避免出现超长链无意识地破坏系统性能。

附:本次演示的项目地址
https://github.com/syshlang/java-design-patterns