委派模式
单独拿出来,因为他不属于23种设计模式,他的基本作用是负责任务的调用和分配任务。和代理模式很像,但是代理模式强调的是代理的过程[代理做了什么],委派模式强调的是做了什么[我该把任务给谁来做得到怎样的结果] 【类比调度中心】。
源码应用
-
DispatcherServlet // 继承自FrameworkServlet ,更高层继承 HttpServlet public class DispatcherServlet extends FrameworkServlet { . . . static { // 读取DispatcherServlet.properties配置,定义了处理器、适配器、异常处理....策略 /** org.springframework.web.servlet.HandlerMapping=org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping,\ org.springframework.web.servlet.function.support.RouterFunctionMapping org.springframework.web.servlet.HandlerAdapter=org.springframework.web.servlet.mvc.HttpRequestHandlerAdapter,\ org.springframework.web.servlet.mvc.SimpleControllerHandlerAdapter,\ org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter,\ org.springframework.web.servlet.function.support.HandlerFunctionAdapter org.springframework.web.servlet.HandlerExceptionResolver=org.springframework.web.servlet.mvc.method.annotation.ExceptionHandlerExceptionResolver,\ org.springframework.web.servlet.mvc.annotation.ResponseStatusExceptionResolver,\ org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver */ try { ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class); defaultStrategies = PropertiesLoaderUtils.loadProperties(resource); } catch (IOException ex) { throw new IllegalStateException("Could not load '" + DEFAULT_STRATEGIES_PATH + "': " + ex.getMessage()); } } . . . /** 处理器策略 */ @Nullable private List<HandlerMapping> handlerMappings; /** 适配器策略 */ @Nullable private List<HandlerAdapter> handlerAdapters; . . . /** * This implementation calls {@link #initStrategies}. */ @Override protected void onRefresh(ApplicationContext context) { initStrategies(context); } /** * 初始化策略到servlet */ protected void initStrategies(ApplicationContext context) { initMultipartResolver(context); initLocaleResolver(context); initThemeResolver(context); initHandlerMappings(context); initHandlerAdapters(context); initHandlerExceptionResolvers(context); initRequestToViewNameTranslator(context); initViewResolvers(context); initFlashMapManager(context); } . . . /** * Initialize the HandlerMappings used by this class. * <p>If no HandlerMapping beans are defined in the BeanFactory for this namespace, * we default to BeanNameUrlHandlerMapping. */ private void initHandlerMappings(ApplicationContext context) { this.handlerMappings = null; if (this.detectAllHandlerMappings) { // Find all HandlerMappings in the ApplicationContext, including ancestor contexts. Map<String, HandlerMapping> matchingBeans = BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false); if (!matchingBeans.isEmpty()) { this.handlerMappings = new ArrayList<>(matchingBeans.values()); // We keep HandlerMappings in sorted order. AnnotationAwareOrderComparator.sort(this.handlerMappings); } } else { try { HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class); this.handlerMappings = Collections.singletonList(hm); } catch (NoSuchBeanDefinitionException ex) { // Ignore, we'll add a default HandlerMapping later. } } } . . . /** * 重写 doService 调用doDispatch。doDispatch方法用来委派任务 */ @Override protected void doService(HttpServletRequest request, HttpServletResponse response) throws Exception { . . . doDispatch(request, response); . . . } /** * 委派模式的思想在这里体现。 * * doDispatch将请求委托给可以处理的处理器来执行,找到支持的适配器来处理 * 和代理模式不同的是,代理模式强调的是过程(我做了什么),委派模式是交给谁来做 */ protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception { HttpServletRequest processedRequest = request; HandlerExecutionChain mappedHandler = null; boolean multipartRequestParsed = false; WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request); try { ModelAndView mv = null; Exception dispatchException = null; try { processedRequest = checkMultipart(request); multipartRequestParsed = (processedRequest != request); // 找到可以处理此次请求的HandlerExecutionChain。内部包含具体的处理器和interceptorList mappedHandler = getHandler(processedRequest); . . . // 找到支持此处理器的适配器策略 HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler()); // 执行拦截器链的前置拦截。从前往后执行 if (!mappedHandler.applyPreHandle(processedRequest, response)) { return; } // 处理器执行 mv = ha.handle(processedRequest, response, mappedHandler.getHandler()); // 执行拦截器后置拦截。从后往前执行。 mappedHandler.applyPostHandle(processedRequest, response, mv); } catch (Exception ex) { dispatchException = ex; } catch (Throwable err) { // As of 4.3, we're processing Errors thrown from handler methods as well, // making them available for @ExceptionHandler methods and other scenarios. dispatchException = new NestedServletException("Handler dispatch failed", err); } processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException); } catch (Exception ex) { triggerAfterCompletion(processedRequest, response, mappedHandler, ex); } . . . } } -
Spring中Delegate结尾的类都是实现了委派模式,如
BeanDefinitionParserDelegate;
优点
- 将调用者和真正的执行者分离,降低了系统的耦合度,符合最少知识原则;
- 结合策略模式来使用,可以做到不修改代码扩展新功能;
缺点
- 需要增加一个调度者,如果业务很复杂可能导致调度者的职责过重
应用场景
- 例如支付,通过委派模式委派给不同的支付策略类处理
- 订单流程可以封装为不同的策略类,根据当前订单处理进度委派给不同的类去处理
- 例如我将OA的流程封装起来,但是根据单据不一样传递至OA的数据不一样,可以以单据为策略,然后再以单据类型委派给不同的策略类处理
- 总之策略+委派是我用的很舒服的设计模式