# 责任链模式ChainOfResponsibility

loading

# 一、概念

# 1、定义

为请求创建一个接收此次请求对象的链。

# 2、类型

行为型

# 3、适用场景

一个请求的处理需要多个对象当中的一个或几个协作处理

# 4、优点

  • 请求的发送者和接受者(请求的处理者)解耦
  • 责任链可以动态组合

# 5、缺点

  • 责任链太长或者处理时间过长,影响性能
  • 责任链有可能过多

# 6、相关设计模式

  • 责任链模式和状态模式

责任链模式中各个对象并不指定下一个处理的对象是谁,只有在客户端设计链条中的顺序以及元素,直到被某个责任链条处理或者整个链条结束。状态模式是让每个状态对象知道自己下一个处理的对象是谁。

# 二、应用

现在模拟课程发布的一个应用场景。首先是课程类:

public class Course {

    private String name;
    private String article;
    private String video;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getArticle() {
        return article;
    }

    public void setArticle(String article) {
        this.article = article;
    }

    public String getVideo() {
        return video;
    }

    public void setVideo(String video) {
        this.video = video;
    }
}
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

审批者类:

public abstract class Approver {

    protected Approver approver;

    public void setNextApprover(Approver approver) {
        this.approver = approver;
    }

    public abstract void deploy(Course course);
}
1
2
3
4
5
6
7
8
9
10

再创建一个手机的审批者和视频的审批者:

public class ArticleApprover extends Approver {

    @Override
    public void deploy(Course course) {
        if (StringUtils.isNotBlank(course.getArticle())) {
            System.out.println(course.getName() + "含有手记,批准");
            if (approver != null) {
                approver.deploy(course);
            }
        } else {
            System.out.println(course.getName() + "不含有手记,不批准,流程结束");
            return;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class VideoApprover extends Approver {

    @Override
    public void deploy(Course course) {
        if (StringUtils.isNotBlank(course.getArticle())) {
            System.out.println(course.getVideo() + "含有视频,批准");
            if (approver != null) {
                approver.deploy(course);
            }
        } else {
            System.out.println(course.getVideo() + "不含有视频,不批准,流程结束");
            return;
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

类图:

责任链

测试类:

public class Test {

    public static void main(String[] args) {
        Approver articleApprover = new ArticleApprover();
        Approver videoApprover = new VideoApprover();

        Course course = new Course();
        course.setName("设计模式");
        course.setArticle("设计模式手机");
        course.setVideo("设计模式视频");

        articleApprover.setNextApprover(videoApprover);
        articleApprover.deploy(course);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

执行结果:

设计模式含有手记,批准
设计模式视频含有视频,批准
1
2

# 三、源码中的应用

# Filter

javax.servlet 包下的 Filter 接口有一个 doFilter() 方法:

    public void doFilter(ServletRequest request, ServletResponse response,
            FilterChain chain) throws IOException, ServletException;
1
2

其中的 FilterChain 参数:

public interface FilterChain {

    /**
     * Causes the next filter in the chain to be invoked, or if the calling
     * filter is the last filter in the chain, causes the resource at the end of
     * the chain to be invoked.
     * 
     * @param request
     *            the request to pass along the chain.
     * @param response
     *            the response to pass along the chain.
     * 
     * @since 2.3
     */
    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

FilterChain 中有很多 Filter,这些 Filter 按照一定逻辑顺序组装成一个链条。这就是责任链模式,具体的某一个 Filter 就是链条中的一个元素。实现 FilterChain 的接口 MockFilterChain,它是为了方便 Spring 测试或者 Mock 使用的。Filter 的实现就比较多了,例如:LoggerContextFilter,它的 doFilter() 方法:

  public void doFilter(ServletRequest request, ServletResponse response,
      FilterChain chain) throws IOException, ServletException {

    LoggerContext lc = (LoggerContext) LoggerFactory.getILoggerFactory();
    ContextSelector selector = ContextSelectorStaticBinder.getSingleton().getContextSelector();
    ContextJNDISelector sel = null;

    if (selector instanceof ContextJNDISelector) {
      sel = (ContextJNDISelector)selector;
      sel.setLocalContext(lc);
    }

    try {
      chain.doFilter(request, response);
    } finally {
      if (sel != null) {
        sel.removeLocalContext();
      }
    }
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

上次更新: 2020-08-21 09:02:51(10 小时前)