1、责任链模式

责任链(Chain of Responsibility)模式就是一个“推卸责任”或者说找到合适的处理对象,不是自己处理的或者处理不了的就交给下一个去处理。这样可以使每个处理对象专注于自己的事情,不是自己的事甩给后面处理,但是这样会使得处理处理延迟,这就需要我们去权衡两者的利弊。
责任链可以弱化“请求方”和“处理方”的关联关系,让各自可以都可成为独立复用的组件。“弱化“请求方”和“处理方”的关联关系”这句话怎么理解呢?就是假如不使用责任链模式,那么请求方或者处理方必须知道谁该处理什么请求,这会降低可复用组件的独立性

2、责任链模式实现

代码UML图如下:
访问数据结构-责任链模式.svg
代码如下:

  1. /**
  2. * 发生问题的类
  3. */
  4. public class Trouble {
  5. private int number;
  6. public Trouble(int number) {
  7. this.number = number;
  8. }
  9. public int getNumber() {
  10. return number;
  11. }
  12. @Override
  13. public String toString() {
  14. return "Trouble{" +
  15. "number=" + number +
  16. '}';
  17. }
  18. }
  1. /**
  2. * 解决问题的抽象类
  3. */
  4. public abstract class Support {
  5. private String name;
  6. private Support next;
  7. public Support(String name) {
  8. this.name = name;
  9. }
  10. public Support setNext(Support next) {
  11. this.next = next;
  12. //关键
  13. return next;
  14. }
  15. //解决问题的步骤
  16. public final void support(Trouble trouble) {
  17. if (resolve(trouble)) {
  18. done(trouble);
  19. } else if (next != null) {
  20. next.support(trouble);
  21. } else {
  22. fail(trouble);
  23. }
  24. }
  25. protected abstract boolean resolve(Trouble trouble) ;
  26. protected void done(Trouble trouble) {
  27. System.out.println(trouble + "is resolved by" + this + ".");
  28. }
  29. protected void fail(Trouble trouble) {
  30. System.out.println(trouble + "cannot be resolved.");
  31. }
  32. }
  1. /**
  2. * 这是一个永远不解决问题的类
  3. */
  4. public class NoSupport extends Support{
  5. public NoSupport(String name) {
  6. super(name);
  7. }
  8. protected boolean resolve(Trouble trouble) {
  9. return false;
  10. }
  11. }
  1. /**
  2. * 只解决编号小于limit的问题
  3. */
  4. public class LimitSupport extends Support{
  5. private int limit;
  6. public LimitSupport(String name, int limit) {
  7. super(name);
  8. this.limit = limit;
  9. }
  10. protected boolean resolve(Trouble trouble) {
  11. if (trouble.getNumber() < limit) {
  12. return true;
  13. }
  14. return false;
  15. }
  16. }
  1. /**
  2. * 只解决奇数编号的问题
  3. */
  4. public class OddSupport extends Support{
  5. public OddSupport(String name) {
  6. super(name);
  7. }
  8. protected boolean resolve(Trouble trouble) {
  9. if (trouble.getNumber() % 2 == 1) {
  10. return true;
  11. }
  12. return false;
  13. }
  14. }
  1. /**
  2. * 只处理特定编号的问题
  3. */
  4. public class SpecialSupport extends Support{
  5. private int number;
  6. public SpecialSupport(String name, int number) {
  7. super(name);
  8. this.number = number;
  9. }
  10. protected boolean resolve(Trouble trouble) {
  11. if (trouble.getNumber() != number)
  12. return false;
  13. else return true;
  14. }
  15. }
  1. public class Main {
  2. public static void main(String[] args) {
  3. Support useless = new NoSupport("useless");
  4. Support limit = new LimitSupport("limit",10);
  5. Support special = new SpecialSupport("special", 222);
  6. Support limit2 = new LimitSupport("limit2", 333);
  7. Support odd = new OddSupport("odd");
  8. //形成指责链
  9. useless.setNext(limit).setNext(special).setNext(limit2).setNext(odd);
  10. //制造各种问题
  11. for (int i = 0; i < 500; i++) {
  12. useless.support(new Trouble(i));
  13. }
  14. }
  15. }

这种责任链模式实现会将请求依次传给下一个处理器,无论前面的处理器有没有处理过请求;另外一种实现是如果请求被处理了,那么将不会传给下一个处理器。
还可以使用数组或者链表来实现责任链模式,即通过遍历数组或者链表里面的处理器即可。

3、责任链模式的应用

最典型的应用就是Tomcat的过滤器,还有Okhttp3中Interceptor以及Netty中ChannelInBoundHandlerAdapter。

3.1、责任链模式如何提高代码的拓展性

责任链模式可以让代码满足“开闭原则”,比如我们需要对用户提交的内容进行敏感词过滤,那么我们可以在相应的方法上添加相关处理逻辑,但是这样就违反了开闭原则。如果使用了责任链模式,那么就可以直接添加一个新的类来处理即可。

4、在框架中的责任链模式代码分析

4.1、Tomcat的ApplicationFilterChain

  1. public final class ApplicationFilterChain implements FilterChain {
  2. private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0];
  3. private int pos = 0;//当前执行到了哪个filter
  4. private int n = 0;//filter的个数
  5. private Servlet servlet = null;
  6. @Override
  7. public void doFilter(ServletRequest request, ServletResponse response)
  8. throws IOException, ServletException {
  9. if( Globals.IS_SECURITY_ENABLED ) {
  10. final ServletRequest req = request;
  11. final ServletResponse res = response;
  12. try {
  13. java.security.AccessController.doPrivileged(
  14. new java.security.PrivilegedExceptionAction<Void>() {
  15. @Override
  16. public Void run()
  17. throws ServletException, IOException {
  18. //该方法会对过滤器进行遍历
  19. internalDoFilter(req,res);
  20. return null;
  21. }
  22. }
  23. );
  24. }
  25. }
  26. }
  27. private void internalDoFilter(ServletRequest request,
  28. ServletResponse response)
  29. throws IOException, ServletException {
  30. // 如果还有过滤器,那么就调用下一个过滤器
  31. if (pos < n) {
  32. ApplicationFilterConfig filterConfig = filters[pos++];
  33. try {
  34. Filter filter = filterConfig.getFilter();
  35. if (request.isAsyncSupported() && "false".equalsIgnoreCase(
  36. filterConfig.getFilterDef().getAsyncSupported())) {
  37. request.setAttribute(Globals.ASYNC_SUPPORTED_ATTR, Boolean.FALSE);
  38. }
  39. if( Globals.IS_SECURITY_ENABLED ) {
  40. final ServletRequest req = request;
  41. final ServletResponse res = response;
  42. Principal principal =
  43. ((HttpServletRequest) req).getUserPrincipal();
  44. Object[] args = new Object[]{req, res, this};
  45. SecurityUtil.doAsPrivilege ("doFilter", filter, classType, args, principal);
  46. } else {
  47. //递归调用下一个过滤器
  48. filter.doFilter(request, response, this);
  49. }
  50. return;
  51. }
  52. }
  53. }
  54. void addFilter(ApplicationFilterConfig filterConfig) {
  55. // 防止同一个过滤器被重复加入
  56. for(ApplicationFilterConfig filter:filters)
  57. if(filter==filterConfig)
  58. return;
  59. if (n == filters.length) {
  60. //扩容
  61. ApplicationFilterConfig[] newFilters =
  62. new ApplicationFilterConfig[n + INCREMENT];
  63. System.arraycopy(filters, 0, newFilters, 0, n);
  64. filters = newFilters;
  65. }
  66. filters[n++] = filterConfig;
  67. }
  68. }