设计模式之职责链模式

定义

使每个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递该请求,
直到有一个对象处理它为止。如公司员工请假,可以批假的领导有部门负责人、副总经理、总经理等,但每个领导可以批准的天数不同,
员工只需要提交申请,不需要知道最终由谁批准。

结构

  • 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也是一个功能链,执行完所有的拦截器才能执行最终的业务处理方法。

总结

优点

  1. 请求者和处理者解耦,请求者不需要知道最终由哪个对象来处理该请求。
  2. 很容易增加新的处理者,不需要修改原有的结构和代码。

缺点

  1. 由于一个请求没有一个明确的处理者,无法保证一定被处理。
  2. 建立链不当可能造成循环调用,导致系统进入死循环。

本质

职责链模式的本质是分离职责,动态组合。分离职责是前提,只有先将复杂的功能分离开,才能合理的规划和定义职责类。

使用场景

  1. 有多个对象可以处理同一个请求,但具体由哪个对象来处理是在运行时动态确定的。
  2. 想要动态地指定处理一个请求的对象集合

参考

大战设计模式【18】—— 职责链模式
设计模式(二十四)——职责链模式(SpringMVC源码分析)
设计模式的征途—14.职责链(Chain of Responsibility)模式
责任链模式(职责链模式)详解
研磨设计模式-书籍

posted @ 2021-09-13 10:05  strongmore  阅读(57)  评论(0编辑  收藏  举报