文档章节

责任链模式(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
05/14
0
0
JAVA设计模式之责任链模式

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

jiangmitiao
2016/03/01
51
0
【设计模式】——责任链模式

职责链模式概述 很多情况下,在一个软件系统中可以处理某个请求的对象不止一个,例如SCM系统中的采购单审批,主任、副董事长、董事长和董事会都可以处理采购单,他们可以构成一条处理采购单的...

u013043341
2017/07/23
0
0

没有更多内容

加载失败,请刷新页面

加载更多

Confluence 6 识别慢性能的宏

Page Profiling 给你了有关页面在载入的时候操作缓慢的邪教,你可以将下面的内容添加到调试(debug)级别: Version 3.1 及其后续版本 设置包名字为 com.atlassian.renderer.v2.components.M...

honeymose
10分钟前
0
0
day93-20180920-英语流利阅读-待学习

时尚之觞:外表光鲜靓丽,其实穷得要命 Lala 2018-09-20 1.今日导读 讲到时尚界,我们脑海里浮现的可能都是模特和设计师光鲜靓丽、从容潇洒的模样。可是,最近在法国出版的一本书却颠覆了我们...

飞鱼说编程
26分钟前
0
0
maven的pom.xml用解决版本问题

maven管理库依赖,有个好处就是连同库的依赖的全部jar文件一起下载,免去手工添加的麻烦,但同时也带来了同一个jar会被下载了不同版本的问题,好在pom的配置里面允许用<exclusion>来排除一些...

JAVA码猿
49分钟前
1
0
20180920 rzsz传输文件、用户和用户组相关配置文件与管理

利用rz、sz实现Linux与Windows互传文件 [root@centos01 ~]# yum install -y lrzsz # 安装工具sz test.txt # 弹出对话框,传递到选择的路径下rz # 回车后,会从对话框中选择对应的文件传递...

野雪球
今天
2
0
OSChina 周四乱弹 —— 毒蛇当辣条

Osc乱弹歌单(2018)请戳(这里) 【今日歌曲】 @ 达尔文:分享花澤香菜/前野智昭/小野大輔/井上喜久子的单曲《ミッション! 健?康?第?イチ》 《ミッション! 健?康?第?イチ》- 花澤香菜/前野智...

小小编辑
今天
40
11

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部