文档章节

责任链模式(Chain Of Responsibility Pattern,对象行为模式)

翰霖学院
 翰霖学院
发布于 2017/07/24 08:56
字数 2570
阅读 5
收藏 0

意图

使多个对象都有机会处理请求,从而避免请求的发送者和接收者时间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求直到有一个对象处理它为止。
责任转送
纯责任链模式:规定一个具体的处理角色只能对请求做出两个动作:自己处理;传给下家,而且在链中必须完成处理。

适用性

在以下条件下使用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对象负责处理它。

效果

降低耦合度

该模式使得一个对象无需直到是其他哪一个对象处理其请求。对象仅需知道该请求会被“正确”地处理。接收者和发送者都没有对方的明确的信息,且链中的对象不需知道链的结构。
结果是,职责链可简化对象的相互连接。它们仅需保持一个指向其后继者的引用,而不需保持它所有的候选接受者的引用。将请求的发送者和接收者解耦。可以简化你的对象,因为它不需要知道链的结构。

增强了给对象指派职责的灵活性

当在对象中分派职责时,职责链给你更多的灵活性。你可以通过在运行时刻对该链进行动态的增加或修改来增加或改变处理一个请求的那些职责。你可以将这种机制与静态的特例化处理对象的继承机制结合起来使用。通过改变链内的成员或调动他们的次序,允许你动态地新增或删除责任。

不保证被接收

既然一个请求没有明确的接收者,那么就不能保证它一定会被处理,该请求可能一直到链的末端都得不到处理。一个请求也可能因该链没有被正确配置而得不到处理。可能不容观察运行时的特征,有碍于排错。

实现

实现后继者链

  1. 定义新的链接(通常在Handler中定义,但也可由ConcreteHandler来定义)
  2. 使用已有的链接(使用已有对象引用来形成后继者链),当已有的链接能够支持你所需的链时,完全可以使用它们。这样你不需要明确定义链接,而且可以节省空间。但如果该结构不能反映应用所需的职责链,那么你必须定义额外的链接。

连接后继者

如果没有已有的引用可定义一个链,那么你必须自己引入它们。这种情况下Handler不仅定义该请求的接口,通常也维护后继链接。这样Handler就提供了HandlerRequest的缺省实现:HandlerRequest向后继者(如果有的话)转发请求。如果ConcreteHandler子类对该请求不敢兴趣,它不需要重新定义转发操作,因为它的缺省实现进行无条件转发。

表示请求

可以有不同的方法表示请求。
1. 硬编码:这种形式方便而且安全,但是你只能转发定义的固定请求。
2. 使用处理函数(钩子函数):这个函数以一个请求码(比如一个整型常数或一个字符串)为参数。这种方法支持请求数目不限,唯一的要求是发送方和接收方在请求如何编码问题上应该达成一致。这种方法更为灵活,但它需要用条件语句来区分请求代码已分派请求。另外,无法用类型安全的方法来传递请求参数,因为他们必须被手动打包和解包。显然,相对于直接调用一个操作来说它不太安全。为解决参数传递问题,我们可使用独立的请求对象来封装请求参数。 Request类可明确地描述请求,而新类型的请求可用它的子类来定义。这些子类可定义不同的请求参数。处理者必须知道请求的类型 (即它们正使用哪一个Request子类)以访问这些参数。为标识请求,Request可定义一个访问器 (accessor)函数以返回该类的标识符。或者,如果实现语言支持的话,接受者可使用运行时的类型信息。

经典例子

经常被使用在窗口系统中,处理鼠标和键盘之类的事件。 当算法牵涉到一种链型运算,而且不希望处理过程中有过多的循环和条件选择语句,并 且希望比较容易的扩充文法,可以采用职责链模式。
工作流(财务报销中的流程审批)、Java中的异常处理、典型现实生活中的推卸责任

SpringMVC

HandlerMapping

public 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 事务模式 对象行为模式)”

© 著作权归作者所有

共有 人打赏支持
翰霖学院
粉丝 0
博文 67
码字总数 45112
作品 0
济南
高级程序员
私信 提问
行为型模式之六:责任链模式

责任链的主要意图是创建一个处理单元链,当每个单元满足阀值后都处理请求。当链建立之后,如果一个单元没有满足,就会尝试下一个单元,依次下去,每个请求都会单独通过链。 责任链类图 责任链...

刀狂剑痴
2015/08/27
11
0
Java中的24种设计模式与7大原则

1,创建型模式 一、抽象工厂模式(Abstract factory pattern): 提供一个接口, 用于创建相关或依赖对象的家族, 而不需要指定具体类. 二、生成器模式(Builder pattern): 使用生成器模式封装一个...

OrionBox
2012/09/12
0
0
Design Patterns in Android:责任链模式

前言 非常抱歉,本系列博客长达半年没更新了,今日偶得灵感,更新一波《设计模式Android篇:责任链模式》。点击此处查看《Design Patterns in Android》系列其他文章。 本文原创作者MichaelX。...

MichaelX
10/30
0
0
移动开发之设计模式- 责任链模式(IOS&Android)

资源 完全参照 责任链模式|菜鸟教程但不包括IOS代码 责任链模式 顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链。这种模式给予请求的类型,对请求...

FlanneryZJ
昨天
0
0
JAVA设计模式之责任链模式

在阎宏博士的《JAVA与模式》一书中开头是这样描述责任链(Chain of Responsibility)模式的: 责任链模式是一种对象的行为模式。在责任链模式里,很多对象由每一个对象对其下家的引用而连接起...

jiangmitiao
2016/03/01
51
0

没有更多内容

加载失败,请刷新页面

加载更多

解析JQuery中each方法的使用

each() 方法规定为每个匹配元素规定运行的函数。写的十分的全面细致,具有一定的参考价值,对此有需要的朋友可以参考学习下。如有不足之处,欢迎批评指正。 概述: each() 方法规定为每个匹配...

前端攻城小牛
8分钟前
1
0
深入解析Vue开发动态刷新Echarts组件的教程

需求背景:dashboard作为目前企业中后台产品的“门面”,如何更加实时、高效、炫酷的对统计数据进行展示,是值得前端开发工程师和UI设计师共同思考的一个问题。今天就从0开始,封装一个动态渲...

peakedness丶
21分钟前
3
0
memcached

memcached 为了避免内存碎片化(传统的内存管理方式是,使用完通过malloc分配的内存后通过free来回收内存,这种方式容易产生内存碎片并降低操作系统对内存的管理效率),采用了 slab allocatio...

Cobbage
21分钟前
2
0
keepalived的介绍及配置高可用集群

12月19日任务 18.1 集群介绍 18.2 keepalived介绍 18.3/18.4/18.5 用keepalived配置高可用集群 集群介绍 根据功能划分为2类:高可用和负载均衡 高可用集群:通常为两台服务器,一台工作,另外...

robertt15
22分钟前
5
0
WiFi攻击的三种方式

导读 WiFi的安全问题已经引起了不少的使用者重视,甚至已经出现草木皆兵的现象。那么黑客到底是如何做到绕过身份验证来获取WiFi使用权的呢?主要有以下三种方式,其中最后一种方式十分简单。 ...

问题终结者
36分钟前
6
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部