设计模式之职责链模式(责任链模式)

职责链模式

一、职责链模式的基本简介

将多个处理器链接为一个流水线,然后让要加工的对象依次经过流水线上的每一个处理器,最后到达客户手中。职责链模式可以类比为人类的工厂,工厂中的产品就是要加工的对象,产品在工厂车间中需要经过若干不同的加工步骤,每一个加工步骤就是一个处理器,工厂中的流水线将若干加工步骤连接在一起,这就构成了职责链,产品依次经过这些流水线,最终到达客户手中。

二、职责链模式的基本构成

在这里插入图片描述

三、组成部分介绍

  1. Handler

Handler是一个抽象的处理器,定义了消息处理的抽象方法,需要由具体的子类实现,这里我们可以观察到在HandlerhandleMsg方法中还接收了一个HandlerChain对象的引用,这是实现处理器链式调用的关键,借助HandlerChain对象可以决定是否将当前消息传递给下一个处理器

  1. ConcreteHandler

具体的处理器,负责实现具体的消息处理逻辑,以及决定是否将消息传递给下一个处理器

  1. HandlerChain

HandlerChain中关联了一组Handler,并对外提供了添加Handler对象的接口,HandlerChain负责将添加的处理器串联起来,组成一个流水线,除此之外,HandlerChain还提供了启动流水线的接口handleMsg(),一旦该函数被调用,整个消息便可以在HandlerChain中的流水线上被依次传递和处理,除非某个Handler阻止了消息的传递。

四、具体实现

职责链模式的实现有两个版本,一个是数组实现,一个是链表实现,通过上面的介绍我们很容易有一个疑问,就是怎么把Handler串联起来,组成一个流水线?其实想想也不难,我们早就学过数据结构中的线性表,线性表不就是一种逻辑上的串联结构中,通过回忆,线性表恰有两种实现方式,一种是使用数组,一种是使用链表,而职责链模式的实现也分为这两个版本:数组版本链表版本。下面我们通过模拟Tomcat中的FilterChain来实现一个简单的职责链模式的demo。

4.1 数组实现版本

4.1.1 类定义
  1. Filter接口

Filter接口提供对Http请求和响应的过滤和处理,对应我们上面UML图中的抽象Handler类

public interface Filter {
    void doFilter(HttpRequest request, HttpResponse response, FilterChain filterChain);
}
  1. FilterChain

FilterChain对应着上面UML图中的HandlerChain,它提供了添加Filter的方法以及启动Filter流水线处理的方法

public class FilterChain {
    private final List<Filter> filterList = new ArrayList<>();

    private int curPos;

    private HttpServlet servlet;

    public FilterChain addFilter(Filter filter) {
        filterList.add(filter);
        return this;
    }

    public void setServlet(HttpServlet servlet) {
        this.servlet = servlet;
    }

    public void doFilter(HttpRequest request, HttpResponse response) {
        if (curPos < filterList.size()) {
            System.out.println("filter[" + curPos + "]处理前");
            filterList.get(curPos++).doFilter(request, response, this);
            curPos--;
            System.out.println("filter[" + curPos + "]处理后");
        } else {
            servlet.serve(request, response);
        }
    }
  1. 其他辅助类

主要包括模拟的HttpRequest请求消息,和HttpReponse响应消息,以及HttpServlet请求和响应处理类

public class HttpRequest {
    public String getMethod() {
        return "GET";
    }
}

public class HttpResponse {
    public void write(String msg) {
        System.out.println(msg);
    }
}

public class HttpServlet {
    public void serve(HttpRequest request, HttpResponse response) {
        System.out.println(request.getMethod());
        response.write("404 Not Found!");
    }
}
  1. 测试代码
public static void main(String[] args) {
    FilterChain filterChain = new FilterChain();
    filterChain.setServlet(new HttpServlet());
    filterChain.addFilter((request, response, filterChain1) -> {
        filterChain1.doFilter(request, response);
    }).addFilter((request, response, filterChain13) -> {
        filterChain13.doFilter(request, response);
    }).addFilter((request, response, filterChain12) -> {
        filterChain12.doFilter(request, response);
    });
    filterChain.doFilter(new HttpRequest(), new HttpResponse());
}
4.1.3 基本原理讲解
  1. FilterChain中维护了一个Filter列表,该列表是数组实现,并且维护了一个curPos指针,用来指示当前经过的是第几个处理器。

  2. 每次调用FilterChain的doFilter方法,都会让curPos+1,为了能让请求继续被下一个Filter处理,我们只需要实现链式调用curPos+1位置上的Filter即可,直到最后一个处理器被调用,这个时候再去调用HttpServlet的处理方法,完成对消息的处理。

  3. 怎么实现链式调用curPos+1位置上的Filter呢?秘密就在于Filter对象本身,通过观察Filter接口,我们发现,该接口处理定义了HttpRequest和HttpResponse两个接收参数外,还定义了一个FilterChain对象的引用。然后观察FilterChain的doFilter方法实现,我们发现,在doFilter中,我们将FilterChain对象本身(this)传递给了下一个Filter,那么我们只需要在每个Filter的doFilter方法中通过filterChain引用,链式调用FilterChain对象的doFilter方法即可。这样链式调用就完成了。
    在这里插入图片描述

4.2 链表实现版本

4.2.1 类的定义
  1. Filter

链表版本的Filter被设置为了一个抽象类,提供了子Filter需要的公有方法,setNextFilter和getNextFilter,分别用于设置和获取当前Filter的后继Filter。

public abstract class Filter {
    private Filter nextFilter;

    public void setNextFilter(Filter nextFilter) {
        this.nextFilter = nextFilter;
    }

    public Filter getNextFilter() {
        return nextFilter;
    }
    
    public abstract void doFilter(HttpRequest request, HttpResponse response, FilterChain fc);
}
  1. FilterChain

链表版本的FilterChlain和数组版本的FilterChain的基本功能是一样的,只不过链表版本的FilterChain采用的是链表结构构建Filter流水线。其中curFilter相当于数组实现中的curPos,指示当前正在执行的Filter对象,链表实现中的Filter流水线的链式调用的本质其实和数组没有差别,在目前这个设计中。FilterChain中的doFilter方法每次调用都会将curFilter指针往后移动,而每个Filter对象又持有FilterChain对象的引用,这样只需要在Filter对象中的doFilter方法中继续调用fc.doFilter即可完成链式调用。一旦curFilter为空,说明所有的Filter都被调用过了,这个时候就可以调用servlet的处理逻辑。

public class FilterChain {
    private Filter headFilter;
    private Filter tailFilter;
    private Filter curFilter;
    private HttpServlet servlet;

    public FilterChain addFilter(Filter filter) {
        filter.setNextFilter(null);
        if (headFilter == null) {
            headFilter = filter;
            curFilter = headFilter;
        } else {
            tailFilter.setNextFilter(filter);
        }
        tailFilter = filter;
        return this;
    }

    public void setServlet(HttpServlet servlet) {
        this.servlet = servlet;
    }

    public void doFilter(HttpRequest request, HttpResponse response) {
        if (curFilter != null) {
            Filter filter = curFilter;
            curFilter = curFilter.getNextFilter();
            filter.doFilter(request, response, this);
        } else {
            servlet.serve(request, response);
        }
    }

}
  1. 测试代码
public static void main(String[] args) {
    FilterChain filterChain = new FilterChain();
    filterChain.addFilter(new Filter() {
        @Override
        public void doFilter(HttpRequest request, HttpResponse response, FilterChain fc) {
            System.out.println("filter1处理前");
            fc.doFilter(request, response);
            System.out.println("filter1处理后");
        }
    }).addFilter(new Filter() {
        @Override
        public void doFilter(HttpRequest request, HttpResponse response, FilterChain fc) {
            System.out.println("filter2处理前");
            fc.doFilter(request, response);
            System.out.println("filter2处理后");
        }
    });
    filterChain.setServlet(new HttpServlet());
    filterChain.doFilter(new HttpRequest(), new HttpResponse());
}
  • 0
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值