责任链模式(Chain Of Responsibility Pattern,对象行为模式)
2017-07-24 00:00
507 查看
摘要: 使多个对象都有机会处理请求,从而避免请求的发送者和接收者时间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求直到有一个对象处理它为止。
责任转送
纯责任链模式:规定一个具体的处理角色只能对请求做出两个动作:自己处理;传给下家,而且在链中必须完成处理。
1. 有多个的对象可以处理一个请求,哪个对象处理该请求运行时候自动确定
2. 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
3. 可处理一个请求的对象集合应被动态指定
(可选)实现后继链(当让对于链子的不同实现,也可以在这个角色中实现后继链)
可访问它的后继者
如果可处理该请求,就处理之;否则将该请求转发给它的后继者
结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。将请求的发送者和接收者解耦。可以简化你的对象,因为它不需要知道链的结构。
使用已有的链接(使用已有对象引用来形成后继者链),当已有的链接能够支持你所需的链时,完全可以使用它们。这样你不需要明确定义链接,而且可以节省空间。但如果该结构不能反映应用所需的职责链,那么你必须定义额外的链接。
1. 硬编码:这种形式方便而且安全,但是你只能转发定义的固定请求。
2. 使用处理函数(钩子函数):这个函数以一个请求码(比如一个整型常数或一个字符串)为参数。这种方法支持请求数目不限,唯一的要求是发送方和接收方在请求如何编码问题上应该达成一致。这种方法更为灵活,但它需要用条件语句来区分请求代码已分派请求。另外,无法用类型安全的方法来传递请求参数,因为他们必须被手动打包和解包。显然,相对于直接调用一个操作来说它不太安全。为解决参数传递问题,我们可使用独立的请求对象来封装请求参数。 Request类可明确地描述请求,而新类型的请求可用它的子类来定义。这些子类可定义不同的请求参数。处理者必须知道请求的类型 (即它们正使用哪一个Request子类)以访问这些参数。为标识请求,Request可定义一个访问器 (accessor)函数以返回该类的标识符。或者,如果实现语言支持的话,接受者可使用运行时的类型信息。
工作流(财务报销中的流程审批)、Java中的异常处理、典型现实生活中的推卸责任
HandlerExecutionChain
敬请期待“命令模式(Command Action 事务模式 对象行为模式)”
意图
使多个对象都有机会处理请求,从而避免请求的发送者和接收者时间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求直到有一个对象处理它为止。责任转送
纯责任链模式:规定一个具体的处理角色只能对请求做出两个动作:自己处理;传给下家,而且在链中必须完成处理。
适用性
在以下条件下使用Responsibility链:1. 有多个的对象可以处理一个请求,哪个对象处理该请求运行时候自动确定
2. 你想在不明确指定接收者的情况下,向多个对象中的一个提交一个请求
3. 可处理一个请求的对象集合应被动态指定
结构
参与者
Handler
定义一个处理请求的接口(可选)实现后继链(当让对于链子的不同实现,也可以在这个角色中实现后继链)
ConcreteHandler
处理它所负责的请求可访问它的后继者
如果可处理该请求,就处理之;否则将该请求转发给它的后继者
Client
向链上的具体处理者(ConcreteHandler)对象提交请求代码
Handler
public abstract class Handler { private Handler nextHandler; private String requestClassName; public Handler setNextHandler(Handler nextHandler){ this.nextHandler = nextHandler; return nextHandler; } public Handler(String requestClassName){this.requestClassName = requestClassName;} public final void request(){ if(isDone()){ System.out.println("由"+requestClassName+"已处理"); }else if(nextHandler!=null){ nextHandler.request(); }else{ System.out.println("未处理"); } } public abstract boolean isDone(); }
ConcreteHandler
public class ConcreteHandler1 extends Handler{ public ConcreteHandler1(String requestClassName) { super(requestClassName); } public boolean isDone() { return false; } } public class ConcreteHandler2 extends Handler{ public ConcreteHandler2(String requestClassName) { super(requestClassName); } public boolean isDone() { return true; } }
Client
public class Client { public static void main(String[] args) { Handler concreteHandler1 = new ConcreteHandler1("concreteHandler1"); Handler concreteHandler2 = new ConcreteHandler2("concreteHandler2"); concreteHandler1.setNextHandler(concreteHandler2); concreteHandler1.request(); } }
协作
当客户提交一个请求时,请求沿链传递直到有一个ConcreteHandler对象负责处理它。效果
降低耦合度
该模式使得一个对象无需直到是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”地处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。将请求的发送者和接收者解耦。可以简化你的对象,因为它不需要知道链的结构。
增强了给对象指派职责的灵活性
当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。通过改变链内的成员或调动他们的次序,允许你动态地新增或删除责任。不保证被接收
既然一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。可能不容观察运行时的特征,有碍于排错。实现
实现后继者链
定义新的链接(通常在Handler中定义,但也可由ConcreteHandler来定义)使用已有的链接(使用已有对象引用来形成后继者链),当已有的链接能够支持你所需的链时,完全可以使用它们。这样你不需要明确定义链接,而且可以节省空间。但如果该结构不能反映应用所需的职责链,那么你必须定义额外的链接。
连接后继者
如果没有已有的引用可定义一个链,那么你必须自己引入它们。这种情况下Handler不仅定义该请求的接口,通常也维护后继链接。这样Handler就提供了HandlerRequest的缺省实现:HandlerRequest向后继者(如果有的话)转发请求。如果ConcreteHandler子类对该请求不敢兴趣,它不需要重新定义转发操作,因为它的缺省实现进行无条件转发。表示请求
可以有不同的方法表示请求。1. 硬编码:这种形式方便而且安全,但是你只能转发定义的固定请求。
2. 使用处理函数(钩子函数):这个函数以一个请求码(比如一个整型常数或一个字符串)为参数。这种方法支持请求数目不限,唯一的要求是发送方和接收方在请求如何编码问题上应该达成一致。这种方法更为灵活,但它需要用条件语句来区分请求代码已分派请求。另外,无法用类型安全的方法来传递请求参数,因为他们必须被手动打包和解包。显然,相对于直接调用一个操作来说它不太安全。为解决参数传递问题,我们可使用独立的请求对象来封装请求参数。 Request类可明确地描述请求,而新类型的请求可用它的子类来定义。这些子类可定义不同的请求参数。处理者必须知道请求的类型 (即它们正使用哪一个Request子类)以访问这些参数。为标识请求,Request可定义一个访问器 (accessor)函数以返回该类的标识符。或者,如果实现语言支持的话,接受者可使用运行时的类型信息。
经典例子
经常被使用在窗口系统中,处理鼠标和键盘之类的事件。 当算法牵涉到一种链型运算,而且不希望处理过程中有过多的循环和条件选择语句,并 且希望比较容易的扩充文法,可以采用职责链模式。工作流(财务报销中的流程审批)、Java中的异常处理、典型现实生活中的推卸责任
SpringMVC
HandlerMappingpublic interface HandlerMapping { /** * Return a handler and any interceptors for this request. The choice may be made * on request URL, session state, or any factor the implementing class chooses. * <p>The returned HandlerExecutionChain contains a handler Object, rather than * even a tag interface, so that handlers are not constrained in any way. * For example, a HandlerAdapter could be written to allow another framework's * handler objects to be used. * <p>Returns {@code null} if no match was found. This is not an error. * The DispatcherServlet will query all registered HandlerMapping beans to find * a match, and only decide there is an error if none can find a handler. * @param request current HTTP request * @return a HandlerExecutionChain instance containing handler object and * any interceptors, or {@code null} if no mapping found * @throws Exception if there is an internal error */ HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception; }
HandlerExecutionChain
package org.springframework.web.servlet; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.springframework.util.CollectionUtils; import org.springframework.util.ObjectUtils; /** * Handler execution chain, consisting of handler object and any handler interceptors. * Returned by HandlerMapping's {@link HandlerMapping#getHandler} method. * 这个HandlerExecutionChain持有一个Interceptor链和一个handler对象, * 这个handler对象实际上就是HTTP请求对应的Controller,在持有这个handler对象的同时, * 还在HandlerExecutionChain中设置了一个拦截器链,通过这个拦截器链中的拦截器, * 可以为handler对象提供功能的增强。要完成这些工作,需要对拦截器链和handler都进行配置, * 这些配置都是在HandlerExecutionChain的初始化函数中完成的。为了维护这个拦截器链和handler, * HandlerExecutionChain还提供了一系列与拦截器链维护相关一些操作。 * @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; private HandlerInterceptor[] interceptors; private List<HandlerInterceptor> interceptorList; private int interceptorIndex = -1; /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute */ public HandlerExecutionChain(Object handler) { this(handler, (HandlerInterceptor[]) null); } /** * Create a new HandlerExecutionChain. * @param handler the handler object to execute * @param interceptors the array of interceptors to apply * (in the given order) before the handler itself executes */ public HandlerExecutionChain(Object handler, HandlerInterceptor... interceptors) { if (handler instanceof HandlerExecutionChain) { HandlerExecutionChain originalChain = (HandlerExecutionChain) handler; this.handler = originalChain.getHandler(); this.interceptorList = new ArrayList<HandlerInterceptor>(); CollectionUtils.mergeArrayIntoCollection(originalChain.getInterceptors(), this.interceptorList); CollectionUtils.mergeArrayIntoCollection(interceptors, this.interceptorList); } else { this.handler = handler; this.interceptors = interceptors; } } /** * Return the handler object to execute. * @return the handler object */ public Object getHandler() { return this.handler; } public void addInterceptor(HandlerInterceptor interceptor) { initInterceptorList().add(interceptor); } public void addInterceptors(HandlerInterceptor... interceptors) { if (!ObjectUtils.isEmpty(interceptors)) { initInterceptorList().addAll(Arrays.asList(interceptors)); } } private List<HandlerInterceptor> initInterceptorList() { if (this.interceptorList == null) { this.interceptorList = new ArrayList<HandlerInterceptor>(); if (this.interceptors != null) { // An interceptor array specified through the constructor this.interceptorList.addAll(Arrays.asList(this.interceptors)); } } this.interceptors = null; return this.interceptorList; } /** * Return the array of interceptors to apply (in the given order). * @return the array of HandlerInterceptors instances (may be {@code null}) */ public HandlerInterceptor[] getInterceptors() { if (this.interceptors == null && this.interceptorList != null) { this.interceptors = this.interceptorList.toArray(new HandlerInterceptor[this.interceptorList.size()]); } return this.interceptors; } /** * 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; } /** * Apply postHandle methods of registered interceptors. */ void applyPostHandle(HttpServletRequest request, HttpServletResponse response, ModelAndView mv) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; interceptor.postHandle(request, response, this.handler, mv); } } } /** * Trigger afterCompletion callbacks on the mapped HandlerInterceptors. * Will just invoke afterCompletion for all interceptors whose preHandle invocation * has successfully completed and returned true. */ void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Exception ex) throws Exception { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = this.interceptorIndex; i >= 0; i--) { HandlerInterceptor interceptor = interceptors[i]; try { interceptor.afterCompletion(request, response, this.handler, ex); } catch (Throwable ex2) { logger.error("HandlerInterceptor.afterCompletion threw exception", ex2); } } } } /** * Apply afterConcurrentHandlerStarted callback on mapped AsyncHandlerInterceptors. */ void applyAfterConcurrentHandlingStarted(HttpServletRequest request, HttpServletResponse response) { HandlerInterceptor[] interceptors = getInterceptors(); if (!ObjectUtils.isEmpty(interceptors)) { for (int i = interceptors.length - 1; i >= 0; i--) { if (interceptors[i] instanceof AsyncHandlerInterceptor) { try { AsyncHandlerInterceptor asyncInterceptor = (AsyncHandlerInterceptor) interceptors[i]; asyncInterceptor.afterConcurrentHandlingStarted(request, response, this.handler); } catch (Throwable ex) { logger.error("Interceptor [" + interceptors[i] + "] failed in afterConcurrentHandlingStarted", ex); } } } } } /** * Delegates to the handler's {@code toString()}. */ @Override public String toString() { if (this.handler == null) { return "HandlerExecutionChain with no handler"; } StringBuilder sb = new StringBuilder(); sb.append("HandlerExecutionChain with handler [").append(this.handler).append("]"); if (!CollectionUtils.isEmpty(this.interceptorList)) { sb.append(" and ").append(this.interceptorList.size()).append(" interceptor"); if (this.interceptorList.size() > 1) { sb.append("s"); } } return sb.toString(); } }
相关模式
Composite Pattern
责任链模式常与Composite Pattern一起使用。这种情况下,一个构件的父构件可作为它的后继。Handler参与者经常会用到Composite Pattern。Command Pattern
丢给Handler参与者的要求有时会用到Command Pattern。敬请期待“命令模式(Command Action 事务模式 对象行为模式)”
相关文章推荐
- 责任链模式(Chain Of Responsibility Pattern,对象行为模式)
- 二十四种设计模式:责任链模式(Chain of Responsibility Pattern)
- [重构到模式-Chain of Responsibility Pattern]把Fizz Buzz招式重构到责任链模式
- 设计模式学习—责任链模式(Chain of Responsibility Design Pattern)
- 行为型模式:责任链模式(Chain of Responsibility Pattern)
- 设计模式 - Chain of Responsibility Pattern(责任链模式)
- 乐在其中设计模式(C#) - 责任链模式(Chain of Responsibility Pattern)
- [重构到模式-Chain of Responsibility Pattern]把哈利波特购书优惠招式重构到责任链模式
- 23种设计模式--责任链模式-Chain of Responsibility Pattern
- [创建型模式系列]Chain of Responsibility Pattern 责任链模式
- 我所理解的设计模式(C++实现)——责任链模式(Chain Of Responsibility Pattern)
- 设计模式(十四)-责任链模式(Chain of Responsibility Pattern)——推卸责任
- 设计模式 - Chain of Responsibility Pattern(责任链模式)
- 极速理解设计模式系列:12.责任链模式(Chain of Responsibility Pattern)
- 极速理解设计模式系列:12.责任链模式(Chain of Responsibility Pattern)
- 我所理解的设计模式(C++实现)——责任链模式(Chain Of Responsibility Pattern)
- 【设计模式】责任链模式(Chain of Responsibility Pattern)
- [重构到模式-Chain of Responsibility Pattern]把Fizz Buzz招式重构到责任链模式
- 如何让孩子爱上设计模式 ——22.责任链模式(Chain of Responsibility Pattern)
- java设计模式——责任链模式(Chain of Responsibility Pattern)