调用像链子,责任链模式

2021-01-06 10:14:42 浏览数 (1)

0x01:责任链模式简介

在责任链模式中,很多对象由每一个对象对其下家的引用而连接起来形成一条链。请求在这个链上进行传递,直到链上的某一个对象决定处理此请求。发出这个请求的客户端并不知道链上的哪一个对象最终处理这个请求,这使得系统可以在不影响客户端的情况下动态地重新组织和分配责任。责任链模式的UML类图如下:

其中,Handler是抽象处理者,定义了一个处理请求的接口;ConcreteHandler是具体处理者,处理它所负责的请求,可访问它的后继者,如果可处理该请求就处理,否则就将该请求转发给它的后继者。主要角色如下:

抽象处理者(Handler):定义出一个处理请求的接口。如果需要接口可以定义出一个方法以设定和返回对下一个处理对象的引用。这个角色通常由一个抽象类或者接口实现。Handler类的聚合关系给出了具体子类对下一个处理对象的引用,抽象方法handleRequest()规范了子类处理请求的操作。

具体处理者(ConcreteHandler):具体处理者接到请求后,可以选择将请求处理掉,或者将请求传给下一个Handler处理。由于具体处理者持有对一个处理对象的引用,因此,如果需要具体处理者可以访问下一个处理对象。

0x02:责任链模式实现

在工作中,免不了需要进行报销。现在与报销这个业务流程来实现责任链模式。约定如下:

  • 报销金额 0 ~ 1W 直属上司审批即可,报销级别为1;
  • 报销金额 1W ~ 5W 部门经理审批即可,报销级别为2;
  • 报销金额 5W 公司负责人审批,报销级别为3;

Request类负责封装请求,具体内容需根据业务产生

代码语言:javascript复制
public class Request {

    private int level;

    public Request(int level) {
        this.level = level;
    }

    public void setLevel(int level) {
        this.level = level;
    }

    public int getLevel() {
            return this.level;
    }
}

Response类负责封装链中返回的结果,具体内容需根据业务产生

代码语言:javascript复制
//处理者返回的数据
public class Response {

    private int result;

    public Response(int result) {
        this.result = result;
    }

    public int getResult() {
        return result;
    }

    public void setResult(int result) {
        this.result = result;
    }


 }

抽象处理者(Handler)

代码语言:javascript复制
public abstract class Handler {

    //下一个处理者
    private Handler nextHandler;  

    public final Response handlerMessage(Request request) {
        Response response = null;
        if(this.getLevel() == request.getLevel()) {    //判断是否是自己的处理级别
            response = this.process(request);
        } else {
            if(this.nextHandler != null) {    //下一处理者不为空
                response = this.nextHandler.handlerMessage(request);
            } else {
                //没有适当的处理者,业务自行处理
            }
        }
        return response;
    }

    //设定下一个处理者
    public void setNext(Handler handler) {
        this.nextHandler = handler;
    }

    //每个处理者可以处理的报销等级
    protected abstract int getLevel();

    //每个处理者都必须实现的处理任务
    protected abstract Response process(Request request);

}

具体处理者(ConcreteHandler)

  • 直属上司
代码语言:javascript复制
/**
 * 直属上司
 *
 */
public class DirectorManager extends Handler {

    @Override
    protected int getLevel() {
        return 1;
    }

    @Override
    protected Response process(Request request) {
        System.out.println("DirectorManager process>>");
        return new Response(1);
    }

}
  • 部门长
代码语言:javascript复制
/**
 * 直属上司
 *
 */
public class DeptManager extends Handler {

    @Override
    protected int getLevel() {
        return 2;
    }

    @Override
    protected Response process(Request request) {
        System.out.println("DeptManager process>>");
        return new Response(2);
    }

}
  • 公司负责人
代码语言:javascript复制
/**
 * 直属上司
 *
 */
public class CompanyManager extends Handler {

    @Override
    protected int getLevel() {
        return 3;
    }

    @Override
    protected Response process(Request request) {
        System.out.println("CompanyManager process>>");
        return new Response(3);
    }

}

责任链模式测试代码

代码语言:javascript复制
public class Client {

    public static void main(String[] args) {
        Handler handler1 = new DirectorManager();
        Handler handler2 = new DeptManager();
        Handler handler3 = new CompanyManager();

        //设置链中的阶段顺序 1->2->3
        handler1.setNext(handler2);
        handler2.setNext(handler3);

        //提交请求返回结果
        Response response = handler1.handlerMessage(new Request(2));
    }

}

0x03:责任链模式在框架的运用

责任链模式的运用可是说非常广泛,下面来了解一下都有哪些框架使用了该设计模式

  • J2EE

在Servlet技术中,分别定义了一个 Filter 和 FilterChain 接口

Filter接口

代码语言:javascript复制
public interface Filter {

    default public void init(FilterConfig filterConfig) throws ServletException {}

    public void doFilter(ServletRequest request, ServletResponse response,
                         FilterChain chain)
            throws IOException, ServletException;

    default public void destroy() {}
}

FilterChain接口

代码语言:javascript复制
public interface FilterChain {

    public void doFilter(ServletRequest request, ServletResponse response)
            throws IOException, ServletException;

}

核心处理类ApplicationFilterChain

代码语言:javascript复制
public final class ApplicationFilterChain implements FilterChain {

 @Override
    public void doFilter(ServletRequest request, ServletResponse response)
        // 省略
    }

    private void internalDoFilter(ServletRequest request,
                                  ServletResponse response)
        throws IOException, ServletException {
          //省略
    }

    //省略
}

在使用Filter时,如果需要交给下一个Filter处理,都会调用如下一段代码:

代码语言:javascript复制
chain.doFilter(request, response);
  • SpringMVC

如果有看过SpringMVC的DispatcherServlet类的源码,可以看到如下一段代码

HandlerExecutionChain类是一个责任链,其中的方法 applyPreHandler() , applyPostHandle() 和 triggerAfterCompletion() 相当于具体的处理类;在 DispatcherServlet 类的 doDispatch() 方法中进行条件判断实现处理的传递。如果想深入了解 HandlerExecutionChain 类的调用关系,可以跟踪一下 DispatcherServlet 类的 doDispatch() 方法。

0 人点赞