责任链模式进阶:与AOP思想的融合与应用

摘要:

  AOP的理念可以很容易抽象出横切关注点,基于AOP理念我们可以将责任链模式中各具体处理角色中共同的实现责任链结构的行为抽象出来并将其模块化,以便进一步提高代码复用率和系统可维护性。实际上,无论是Java Web中的过滤器,还是Struts2中的Interceptor,它们都是责任链模式与AOP思想互相融合的巧妙实践。为了更进一步理解AOP (Aspect-Oriented Programming,AOP) 和 CoR (Chain of Responsibility),本文还概述了Filter,并手动模拟了Java Web中的过滤器机制。最后,我们结合Struts2的源码和文档解释了拦截器的工作原理,更进一步剖析了AOP理念和CoR模式在Java中的应用,同时也有助于了解Struts2的原理。



版权声明:

本文原创作者:书呆子Rico

作者博客地址:http://blog.csdn.net/justloveyou_/



友情提示:

  关于责任链模式的介绍共分为两篇,上篇《责任链模式综述(基础篇)》主要综述了责任链模式的提出动机、原理结构、典型实现和应用场景,并结合具体实例展现了其灵活性、可插拔性和松耦合性。本篇《责任链模式进阶:与AOP思想的融合与应用》主要引入了AOP理念,并在此基础上进一步将责任链结构的实现用切面抽象出来,使得各个具体处理者只需关注自身必须实现的功能性需求。我们知道,无论是Java Web中的过滤器还是Struts2中的 Interceptor,它们都是责任链模式与AOP思想互相融合的巧妙实践。为了更进一步理解AOP和CoR,本篇概述了Filter的提出动机、工作原理和使用流程,并手动模拟了Java Web中的过滤器机制。此外,我们还结合Struts2的源码和文档解释了拦截器的工作原理,更进一步剖析了AOP理念和CoR模式在Java中的应用,同时也有助于了解Struts2的原理。

  为了更好地理解本篇内容,请各位看官先对责任链模式有一个基本的了解或者先阅读本篇的姊妹篇《《责任链模式综述(基础篇)》


一. AOP思想与责任链模式

  面向对象(Object-Oriented) 的分析和设计方法可以将真实世界的实体抽象成类和对象,从而实现了从问题域到软件的转换,这种方法能完美的抽象出问题域中的角色。但是,不同的角色可能有着共同的行为,这种共同的行为被称为 横切关注点。利用面向对象的方法不能很好地抽象出 横切关注点,从而导致了类间耦合度高、代码复用率低(冗余)等问题。面向切面的编程思想(Aspect-Oriented Programming,AOP)就是为了解决 横断关注点的抽象 而诞生的。

  AOP的核心思想允许将分散在类中的共同逻辑(行为)分离出来,将OOP不能很好处理地横切关注点抽象在“切面”之中。其中,“切面” 是在AOP思想中引入的一种 新的编程单位,它使得 横切关注点模块化 ,这对现有的设计模式产生了非常重大的影响。

  用传统的面向对象方法实现责任链模式虽然能够满足责任链模式要求的一切特征,在应用上也有很多实例,但是仍然存在者一些明显的缺陷和不足。比如,各个请求处理者除了实现自身应当处理的逻辑外还要实现责任链的结构(即successor属性及其Setter),也就是说,责任链的建立和指派包含在实现角色的类中,并没有抽象出来,这直接导致责任链的指派不够灵活。

  AOP 思想的精髓能够将横向的关注点分离出来,这大大提高了我们认识世界和抽象世界的能力。实际上,责任链模式的缺陷主要在于具体实现角色的对象中存在着共同的行为——实现责任链结构的行为,而这些行为并没有被抽象出来,而用 AOP 改进责任链模式的关键就是要将责任链结构的实现用切面抽象出来,使得各个对象只关注自身必须实现的功能性需求。实际上,用AOP思想实现责任链模式时仍然保留了 Client,Handler 和 ConcreteHandler 三个角色,不同点是增加了实现责任链的切面,即 HandlerChain,下图反映了融合AOP思想后的责任链模式(以Filter为例)。利用AOP理念来改进责任链模式可以准确地分离出责任链模式中不同角色的共同行为。

            

  

  实际上,无论是 Java Web 中的 Filter,还是 Struts2 中的 Interceptor,它们都是 责任链模式AOP思想 互相融合的巧妙实践。


二. Filter 概述

  在我的专栏《Java Web 成神之路》中,已经对 Java Web 基础内容 JSP/Servlet 内容进行了概述。事实上,Servlet API 还提供了一个重要接口 —— Filter。在我们开发 Web 应用时,若编写的Java类实现了这个接口,那么我们就可以将这个 Java 类称为一个过滤器(Filter)。Filter 可以认为是 Servlet 的一种加强版,它主要用于 对用户请求进行预处理 以及 对服务器响应进行后处理,是个 典型的处理链下面的图示形象地反映了 Filter 的工作流程。

           

  当客户端发出Web资源的请求时,Web服务器根据应用程序配置文件设置的过滤规则进行检查,若客户请求满足过滤规则,则对客户请求/响应进行过滤(拦截),期间我们可以对请求信息 (请求头和请求数据)进行检查或改动,然后对请求放行以便由过滤链中的其他过滤器进行处理,最后把请求/响应交给请求的Web资源(Servlet)处理。同样地,在这个过程中我们可以修改响应信息,从而完成一定的任务,其工作原理如下图所示(本图来自于博文《JAVA学习篇–javaweb之Filter详解》):

            

  过滤链的好处是,发出请求的客户端并不知道链上的哪一个过滤器将处理这个请求,这使得系统可以在不影响客户端的情况下 动态地重新组织链和分配责任,并且在执行过程中的任何时候都可以打断,只要不执行chain.doFilter()就不会再执行后面的过滤器和请求的内容,这显然可以看作是 非纯责任链模式 的一种典型实现。



  更多关于 Java Web 中 过滤器机制 的介绍,请移步我的博客 《Java Web 基础 — Filter 综述》


三. AOP、责任链模式与 JavaWeb 中的 Filter

  实质上,Filter 的实现既体现了AOP的理念,也体现了责任链模式的精髓。AOP的主要的意图是将日志记录、性能统计、安全控制、事务处理、异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非主导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。以处理中文字符乱码问题为例,它并非是业务逻辑的内容却又分布在各个请求处理器中,所以对于这些内容的处理,我们就可以基于AOP的思想将其提取出来(AOP中的切面),使用Filter进行整体设置。这种方式相当于对类中的内容做进一步的抽象,使我们的系统更加灵活,更加能应对变化,也进一步提高了代码复用。

  此外,Filter 的实现体现了责任链模式的精髓,即将请求的发送者与请求的处理者解耦,从而使得系统更灵活,也更容易扩展。就像Servlet规范对Filter描述的那样,过滤链是由Servlet容器提供给开发者的一种过滤器调用的视图,过滤器使用过滤链去调用链中的下一个过滤器去处理请求,特别地,如果当前过滤器时过滤链中的最后一个过滤器,过滤链将把它交给相应的资源处理器(Servlet)进行处理。更进一步地说,使用过滤链对请求进行过滤的好处就是,发出请求的客户端并不知道链上的哪一个过滤器将处理这个请求,这使得系统可以在不影响客户端的情况下,动态地重新组织链和分配责任。并且,在执行过程中的任何时候都可以直接返回结果,也就是说,只要不执行 chain.doFilter() 就不会对请求放行,也就不会再执行后面的过滤器和请求的内容。这显然可以看作是 非纯责任链模式 的一种典型实现。

  显然,FilterChain 本身就是对责任链切面的抽象,是对传统责任链模式的一个改进,整个 Filter 机制本身也是AOP思想与责任链模式的融合的最佳实践。



  特别地,为了大家更好地理解AOP理念和责任链模式在 JavaWeb 中的 Filter 中的应用,我们专门写了一个中文解码过滤器,其实现了对中文乱码的统一处理,无论请求方式是 GET 还是 POST。在这里,Filter 相当于责任链模式中的抽象处理者,而 DecodeFilter 实现了Filter接口,相当于责任链模式中的具体处理者,特别地,ServletAPI 对 FilterChain 的抽象则是 AOP 思想的重要体现,也就是将责任链结构的实现用切面(FilterChain)抽象出来了,准确地分离出责任链模式中不同角色的共同行为(责任链的构建与维护)。

/**
 * Description: 使用 Filter 解决 GET/POST 提交的中文乱码
 * @author rico
 * @created 2017-3-4 上午10:55:06
 */
public class DecodeFilter implements Filter {

    /**  指定编码方式,默认 utf-8   (@author: rico) */
    private String encoding;    // Filter 参数

    @Override
    public void destroy() {
        this.encoding = null;
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse response,
            FilterChain chain) throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) req;

        // 重新编码后的请求
        HttpServletRequest newReq = null;

        // 获取请求方式
        String method = request.getMethod();

        if ("POST".equalsIgnoreCase(method)) {          // POST请求的处理方式
            request.setCharacterEncoding(encoding);
            newReq = request;
        } else {             // GET请求的处理方式
            //  匿名内部类:最终提供给我们的是一个匿名子类对象
            newReq = new HttpServletRequestWrapper(request) {  // HttpServletRequest 接口的实现类   

                // 重写对请求参数所有可能的获取方式
                @Override
                public String getParameter(String name) {
                    String value = super.getParameter(name);
                    if (value != null) {
                        value = this.transCoding(value);
                    }
                    return value;
                }

                // 重写对请求参数所有可能的获取方式
                @Override
                public String[] getParameterValues(String name) {
                    String[] values = super.getParameterValues(name);
                    if (values == null) {
                        return values;
                    }
                    for (int i = 0; i < values.length; i++) {
                        values[i] = this.transCoding(values[i]);
                    }
                    return values;
                }

                // 重写对请求参数所有可能的获取方式
                @Override
                public Map<String, String[]> getParameterMap() {
                    Map<String, String[]> map = super.getParameterMap();
                    Map<String, String[]> result = new HashMap<String, String[]>();
                    Set<Map.Entry<String, String[]>> entrySet = map.entrySet();
                    for (Map.Entry<String, String[]> set : entrySet) {
                        String name = set.getKey();
                        String[] values = set.getValue();
                        for (int i = 0; i < values.length; i++) {
                            values[i] = values[i];
                        }
                        result.put(name, values);
                    }
                    return result;
                }

                // 代码重用,对中文字符进行解码
                public String transCoding(String value) {
                    try {
                        value = new String(value.getBytes("iso-8859-1"),
                                encoding);
                    } catch (UnsupportedEncodingException e) {
                        System.out.println(this.getClass().getName()
                                + " 发生转码错误: 从 " + "iso-8859-1" + " 到 "
                                + encoding);
                        e.printStackTrace();
                    }
                    return value;
                }
            };
        }

        // AOP 思想的重要体现,将请求交给其下家继续进行处理,不纯的责任链模式
        chain.doFilter(newReq, response);
    }

    @Override
    public void init(FilterConfig config) throws ServletException {
        // 从配置文件获取编码参数
        encoding = config.getInitParameter("encoding");
        encoding = encoding == null ? "utf-8" : encoding;
    }
}


  要想让该过滤器起作用,还必须将其配置到 Web 中,即需要在 web.xml 中添加如下描述片段。需要注意的是,当一个Web应用包含多个过滤器时,WEB容器会根据其注册顺序进行调用,也就是说,在web.xml文件中越靠前,越先被调用。因此,若想让该过滤器能够对Struts2应用起作用,则必须将其配置到Struts2过滤器前面。

<!-- 当一个Web应用包含多个过滤器时,根据其注册顺序进行调用:在web.xml文件中越靠前,越先被调用 -->
<!-- 因此,若想让该过滤器能够对Struts2应用起作用,则必须将其配置到Struts2过滤器前面 -->
    <filter>
        <filter-name>DecodeFilter</filter-name>
        <filter-class>cn.edu.tju.rico.filter.DecodeFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>utf-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>DecodeFilter</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

   这样,当客户端发出Web资源的请求时,Web容器就会根据应用程序配置文件设置的过滤规则进行检查,由于我们设置的是对所有请求进行过滤(/*),因此我们可以对请求参数进行解码,然后依次通过过滤器链的其他过滤器,最后把请求交给请求的Web资源(Servlet)处理。需要注意的是,在本案例中,我们只对请求做了预处理,而没有对响应做后处理。这正好印证了J2EE中对FilterChain的描述:“ Filters use the FilterChain to invoke the next filter in the chain, or if the calling filter is the last filter in the chain, to invoke the resource at the end of the chain。”


四. 手动模拟 Java Web 中的过滤器 Filter

  为了更好的体会AOP思想和责任链模式,我们下面手动模拟了 Java Web 中的过滤器 Filter 的实现,其所模拟的流程与Filter的作用流程相同,如下图所示。

           

  在本实现中,我们包含一个抽象 Filter,三个具体的 Filter,包括 HTMLFilter,SensitiveFilter 和 FaceFilter; FilterChain 用于对处理链(责任链切面)的抽象。此外,Request 和 Response 用于对请求消息和响应消息的抽象,Client 用于对客户端的抽象,其类图如下所示:

            

  下面给出各抽象模块的具体实现,需要指出的是,本示例参考于马士兵老师对责任链模式的讲解,但对其做了改进,尤其是关于 FilterChain 的设计改进(只需接收 Request 和 Response),使其与 Servlet API 中 FilterChain 相一致。



1、抽象处理者:Filter

public interface Filter {

    //每个Filter均为FilterChain的成员, Filter持有FilterChain的引用,以便调用链条中的各处理者
    void doFilter(Request request, Response response, FilterChain chain);
}


2、具体处理者:HTMLFilter,SensitiveFilter 和 FaceFilter

// 将请求消息中的"<>"替换成"[]"
public class HTMLFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        // process HTML Tag
        String msg = request.getRequest().replace("<", "[").replace(">", "]");
        request.setRequest(msg);

        chain.doFilter(request, response);

        response.setResponse(response.getResponse() + "--->HTMLFilter");
    }
}

//将请求消息中的"被就业"替换成"就业"
class SensitiveFilter implements Filter {

    @Override
    public void doFilter(Request request, Response response, FilterChain chain) {
        String msg = request.getRequest().replace("被就业", "就业");
        request.setRequest(msg);

        chain.doFilter(request, response);

        response.setResponse(response.getResponse() + "--->SensitiveFilter");
    }
}

// 将请求消息中的":)"替换成"笑脸"
class FaceFilter implements Filter {

    public void doFilter(Request request, Response response, FilterChain chain) {
        String msg = request.getRequest().replace(":)", "笑脸");
        request.setRequest(msg);

        chain.doFilter(request, response);

        response.setResponse(response.getResponse() + "--->FaceFilter");
    }
}


3、过滤链的抽象:FilterChain


// 对过滤链的抽象(横切关注点),是多个过滤器的聚集,本质上,FilterChain 也可以看作是一个大的Filter
public class FilterChain {

    List<Filter> filters = new ArrayList<Filter>();
    int index = 0;

    // 链式编程
    public FilterChain addFilter(Filter filter){
        filters.add(filter);
        return this;    // 返回自身
    }

    public void doFilter(Request request, Response response) {
        if(index == filters.size()) return;
        Filter filter = filters.get(index);
        index++;
        filter.doFilter(request, response, this);
    }
}


4、请求和响应的抽象:Request 和 Response

// 对请求消息的抽象
public class Request {

    // 请求消息
    private String request;

    public String getRequest() {
        return request;
    }

    public void setRequest(String request) {
        this.request = request;
    }

}

// 对响应消息的抽象
class Response {

    // 响应消息
    private String response;

    public String getResponse() {
        return response;
    }

    public void setResponse(String response) {
        this.response = response;
    }

}

5、客户端的抽象:Client

public class Client {
    public static void main(String[] args) {
        // 待处理消息
        String msg = "大家好 :),<script>,敏感,被就业,网络授课没感觉...";

        // 设置请求消息
        Request request = new Request();
        request.setRequest(msg);

        // 设置响应消息
        Response response = new Response();
        response.setResponse("Response");

        // 设置处理链
        FilterChain chain = new FilterChain();
        chain.addFilter(new HTMLFilter()).addFilter(new SensitiveFilter())
                .addFilter(new FaceFilter());

        // 开始处理
        chain.doFilter(request, response);

        // 消息的预处理结果
        System.out.println(request.getRequest());

        // 消息的后处理结果
        System.out.println(response.getResponse());
    }
}/* Output(完全一致):
        大家好 笑脸,[script],敏感,就业,网络授课没感觉...
        Response--->FaceFilter--->SensitiveFilter--->HTMLFilter
 *///:~


  实际上,本示例基本模拟了Java Web 中过滤器的工作流程,也反映了AOP思想和责任链模式的精髓。 对于一个给定的请求消息,我们可以从下图中的方法调用栈中看出,将依次由 HTMLFilter,SensitiveFilter 和 FaceFilter 三者进行预处理,最后再依次由 FaceFilter,SensitiveFilter 和 HTMLFilter 处理(这个可以从输出中看出)。

              

  实际上,FilterChain 本身也可以看作是一个大的Filter,更进步地说,FilterChain 本身也可以实现 Filter 接口,这样做的优点是,我们不但可以在客户端可以任意添加具体的过滤器,还可以添加过滤链;但带来的缺点是将 FilterChain 和 Filter 耦合在了一起,也就是说,FilterChain与Filter的doFilter方法必须一样,而实际上FilterChain的doFilter方法并不需要FilterChain参数。花开生两面,有利就有弊,读者可以尝试让FilterChain 本身实现 Filter 接口,体会一下这个思想。


五. Struts2 中AOP与COR模式的体现:拦截器

  拦截器(Interceptor)是Struts2最强大的特性之一,是struts2的核心,实际上我们完全可以把Struts2看作是一个空的容器,而大量的內建拦截器(包括但不仅限于请求参数的解析、 类型转化、异常处理、数据校验,文件上传)完成了该框架的大部分工作。拦截器可以让我们在Action和Result被执行之前或之后进行一些处理(如下图所示),同时它也可以让我们将通用的代码模块化并作为可重用的类,这正是AOP的精髓,也是AOP的一种实现策略。此外,我们知道Struts2的拦截器是 可插拔式的设计,也就是说,若我们需要使用某个拦截器,只需在配置文件中应用该拦截器即可;若我们不需要使用该拦截器,只需要在配置文件中取消该拦截器。最重要的是,无论我们是否应用该拦截器,其对我们的 Struts2 没有任何影响,这正是责任链模式的精髓所在。

                



1、Struts2 对拦截器的介绍

  下面四段文字是Struts2官方对Interceptor的介绍,揭示了拦截器的提出动机、作用原理和配置流程,并折射出其对AOP理念和CoR模式的理解和使用,为保证原汁原味,本人不作进一步翻译,并将原文摘抄如下:

  Many Actions share common concerns. Some Actions need input validated. Other Actions may need a file upload to be pre-processed. Another Action might need protection from a double submit. Many Actions need drop-down lists and other controls pre-populated before the page displays.

  The framework makes it easy to share solutions to these concerns using an “Interceptor” strategy. When you request a resource that maps to an “action”, the framework invokes the Action object. But, before the Action is executed, the invocation can be intercepted by another object. After the Action executes, the invocation could be intercepted again. Unsurprisingly, we call these objects “Interceptors.”

  Interceptors can execute code before and after an Action is invoked. Most of the framework’s core functionality is implemented as Interceptors. Features like double-submit guards, type conversion, object population, validation, file upload, page preparation, and more, are all implemented with the help of Interceptors. Each and every Interceptor is pluggable, so you can decide exactly which features an Action needs to support.

  Interceptors can be configured on a per-action basis. Your own custom Interceptors can be mixed-and-matched with the Interceptors bundled with the framework. Interceptors “set the stage” for the Action classes, doing much of the “heavy lifting” before the Action executes.

  

  这四段的介绍正是AOP理念的精髓,也就是对横切关注点的抽象,将分散在类中的共同逻辑(行为)分离出来,将OOP理念不能很好处理地横切关注点抽象在“切面”之中,以增强代码复用和灵活性。当然,这也是 Interceptor 的设计理念。此外,拦截器可插拔的设计背后正是CoR模式的应用。



2、结合源码分析Struts2拦截器背后的原理

  我们知道,大部分时候拦截器方法都是通过代理的方式来调用的。当请求到达Struts2的ServletDispatcher时,Struts2会查找配置文件,并根据其配置实例化相对的拦截器对象,然后串成一个列表(list),以便最后由容器依次调用列表中的拦截器作对请求/响应做进一步处理。我们可以在 DefaultActionInvocation 类中找对应的Struts源码如下:

public void init(ActionProxy proxy) {
    ...
    // get a new List so we don‘t get problems with the iterator if someone changes the list
    // 将所有拦截器对象串成一个列表,以便容器调用
    List<InterceptorMapping> interceptorList = new ArrayList<InterceptorMapping>(proxy.getConfig().getInterceptors());
    interceptors = interceptorList.iterator();
}

  同时,我们可以通过调试观察到上面所提到的拦截器列表,如下图所示:

              



  事实上,我们之所以能够如此灵活地使用拦截器,完全归功于“动态代理”的使用。动态代理是代理对象根据客户的需求做出不同的处理。也就是说,对客户而言,其只要知道一个代理对象就行了。特别地,在 Struts2 中,当Action请求到来的时候,会由系统的代理生成一个Action的代理对象,由这个代理对象调用Action的execute()或指定的方法,并在struts.xml中查找与该Action对应的拦截器。如果有对应的拦截器,就在Action的方法执行前(后)调用这些拦截器;如果没有对应的拦截器,则直接执行Action的方法。其中Struts2 对拦截器的调用,是通过ActionInvocation来实现的,代码如下:

public String invoke() throws Exception {
    String profileKey = "invoke: ";
    try {
            UtilTimerStack.push(profileKey);

            if (executed) {
                throw new IllegalStateException("Action has already executed");
            }

            // 由容器依次调用拦截器链中的各拦截器
            if (interceptors.hasNext()) {
                final InterceptorMapping interceptor = (InterceptorMapping) interceptors.next();
                String interceptorMsg = "interceptor: " + interceptor.getName();
                UtilTimerStack.push(interceptorMsg);
                try {
                    // 不断从拦截器栈中取出新的拦截器,并调用拦截器的intercept方法
                    resultCode = interceptor.getInterceptor().intercept(DefaultActionInvocation.this);
                }finally {
                    UtilTimerStack.pop(interceptorMsg);
                }
            } else {
                // 若拦截器栈中所有的拦截器都已调用,则开始调用Action的指定方法进行业务逻辑的处理
                resultCode = invokeActionOnly();
            }

            // 其余代码省略

  

  同时,我们可以通过调试观察到方法调用栈(拦截器调用栈),如下图所示:

            



  总的来说,Struts2 的拦截器又是AOP理念和责任链模式融合的又一次成功实践。


六. 总结

  AOP的理念可以很容易抽象出横切关注点,基于AOP理念我们可以将责任链模式中各具体处理角色中共同的实现责任链结构的行为抽象出来并将其模块化,以便进一步提高代码复用率和系统可维护性。实际上,无论是Java Web中的过滤器,还是Struts2中的Interceptor,它们都是责任链模式与AOP思想互相融合的巧妙实践。为了更进一步理解AOP和CoR,本文还概述了Filter的提出动机、工作原理和使用流程,并手动模拟了Java Web中的过滤器机制。最后,我们结合Struts2的源码和文档解释了拦截器的工作原理,更进一步剖析了AOP理念和CoR模式在Java中的应用,同时也有助于了解Struts2的原理。


七. 更多

  更多关于 protected 关键字 的介绍, 请移步我的博文《Java 访问权限控制:你真的了解 protected 关键字吗?》

  更多关于 Java Web 中 过滤器机制 的介绍,请移步我的博客 《Java Web 基础 — Filter 综述》

  更多对 责任链模式的提出动机、原理结构、典型实现和应用场景等切面的介绍, 请移步本文的姊妹篇《责任链模式综述(基础篇)》


引用

《基于AOP的责任链模式改进研究》

Java程序员从笨鸟到菜鸟之(四十六)细谈struts2(八)拦截器的实现原理及源码剖析

时间: 2024-10-10 13:38:18

责任链模式进阶:与AOP思想的融合与应用的相关文章

责任链模式综述(基础篇)

摘要: 本篇综述责任链模式的提出动机.原理结构.典型实现和应用场景,并结合具体实例展现了其灵活性.可插拔性和松耦合性.首先,结合我们日常生活中"打扑克"的例子引出了责任链模式产生动机,并揭示了其应用场景.紧接着,我们概述了责任链模式的内涵和结构,即通过建立一条责任链来组织请求的处理者,请求将沿着链进行传递,而请求发送者无须知道请求在何时.何处以及如何被处理,实现了请求发送者与处理者的解耦.此外,本文给出了责任链模式的典型实现和并结合具体实例介绍其使用方式,以便我们更好体会其优点. 版权

Java进阶篇设计模式之八 ----- 责任链模式和命令模式

前言 在上一篇中我们学习了结构型模式的享元模式和代理模式.本篇则来学习下行为型模式的两个模式, 责任链模式(Chain of Responsibility Pattern)和命令模式(Command Pattern). 责任链模式 简介 责任链模式顾名思义,就是为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式.在这种模式中,通常每个接收者都包含对另一个接收者的引用.如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接

大量逻辑判断优化的思路——责任链模式复习总结及其和状态模式对比

俗话说,自己写的代码,6个月后也是别人的代码……复习!复习!复习!涉及的总结知识点如下: 责任链模式概念和例子 使用的条件 和状态模式的比较分析 责任链的优缺点 纯的责任链和不纯的责任链 javax.servlet.Filter#doFilter()方法源码分析 基于AOP思想,模拟一个拦截器 前面说了一个状态模式,总结过程中发现和这个责任链的使用场景很类似,都是为了解耦大量复杂业务逻辑判断的,那么他们有什么不同呢?回忆状态模式——状态模式允许通过改变对象的内部状态而改变对象自身的行为,这个对象

责任链模式

案例分析 责任链模式可以通过形象的生活例子进行解读,不管是前端攻城狮还是后端攻城狮,责任链的思想都有所体现(框架之中) 击鼓传花 老太和一群姑娘准备玩击鼓传花的游戏,于是找来了一个击鼓的人,游戏规则就是:随着鼓点声音,从她们之间传递一束花,鼓声落,传花停.花最后传递到那个姑娘的手中,那么就由她来给大家即兴赋诗一首. 那么击鼓的人并不需要知道玩游戏的这些人是谁,只需要击鼓即可,相当于客户端发送一个请求,请求在这些姑娘之间传递,总会有一个姑娘最后接到花,给大家赋诗.(一层层的传递请求,总会有一层来对

chainOfResponsibility责任链模式

责任链(Chain of Responsibility)模式 : 责任链模式是对象的行为模式.使多个对象都有机会处理请求,从而避免请求的发送者和接受者直接的耦合关系.将这些处理对象连成一条链,沿着这条链传递该请求,直到有一个对象处理它为止.责任链模式强调的是每一个对象及其对下家的引用来组成一条链,利用这种方式将发送者和接收者解耦,类图如下: 通过上图可以看出责任链模式有两个角色: 抽象处理者(Handler)角色 :定义一个请求的接口.如果需要可以定义个一个方法用来设定和返回下家对象的引用. 具

设计模式之责任链模式20170717

行为型设计模式之责任链模式: 一.含义 责任链模式的核心在"链"上,"链"是由多个处理者(对象)组成的,由这条链传递请求,直到有对象处理它为止(在链中决定谁来处理这个请求),并返回相应的结果 二.代码说明 1.主要有两个角色 1)处理者 它能够对请求做出处理(请求得到处理则直接返回,否则传到下一个处理者),设置下一个处理者(这两个操作可以抽象出来), 同时每个处理者都有一个相应的处理级别,以及具体的处理操作(父类实现请求传递,子类实现请求处理) 2)被处理者(请求者

GOF业务场景的设计模式-----责任链模式

定义:使多个对象都有机会处理请求,从而避免了请求的发送者和接收者之间的耦合关系.将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止. 首先来看一段代码: public void test(int i, Request request){ if(i==1){ Handler1.response(request); }else if(i == 2){ Handler2.response(request); }else if(i == 3){ Handler3.response(req

iOS设计模式--责任链模式

何为责任链模式? 责任链模式的主要思想是,对象引用了同一类型的另一个对象,形成一条链.链中的每个对象实现了同样的方法,处理对链中第一个对象发起的同一个请求.如果一个对象不知道如何处理请求,它就把请求传递给下一个响应者. 责任链模式:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间发生耦合.此模式将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止. 何时使用责任链模式? @:有多个对象可以处理请求,而处理程序只有在运行时才能确定. @:向一组对象发出请求,而不想显示指

责任链模式妙用

一说到「设计模式」,可能很多人都有听过. 但是如果真的要你说说应用场景,可能会有点「难以描述」. 除了应用场景比较多的单例模式你能够信手拈来,其他的可能会觉得有点难以掌握.也许压根都没用过. 今天,通过本篇文章,让你对责任链模式也能够信手拈来. 本篇文章通过实际项目中的例子来让你认识何为责任链模式. 定义 百度百科的介绍:责任链模式是一种设计模式.在责任链模式里,很多对象由每一个对象对其下家的引用而连接起来形成一条链.请求在这个链上传递,直到链上的某一个对象决定处理此请求.发出这个请求的客户端并