尚硅谷设计模式学习(二十四)职责链模式

以学校采购项目引出职责链模式

采购员采购教学器材
如果金额小于等于  5000,由教学主任审批
如果金额小于等于  10000,由院长审批
如果金额小于等于  30000,由副校长审批
如果金额超过  30000 以上,有校长审批

传统方式

if(x <= 5000){
    教导主任处理
}else if(x > 5000 && x <= 10000){
    院长处理
}else if(x > 10000 && x < 50000){
    副校长处理
}else{
    校长处理
}

客户端这里会使用到分支判断来对不同的采购请求处理, 这样就存在如下问题

  • 如果各个级别的人员审批金额发生变化,在客户端的也需要变化
  • 客户端必须明确的知道有多少个审批级别和访问
  • 这样对一个采购请求进行处理和Approver  (审批人)  就存在强耦合关系,不利于代码的扩展和维护

一、职责链模式

1、基本介绍

职责链模式(Chain  of Responsibility  Pattern),又叫责任链模式,为请求创建了一个接收者对象的链。这种模式对请求的发送者和接收者进行解耦。

职责链模式通常每个接收者都包含对另一个接收者的引用。如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。

属于行为型模式


Handler:抽象的处理者,定义了一个处理请求的接口。
ConcreteHandlerA ,  B :具体的处理者,处理它自己负责的请求,可以访问它的后继者(即下一个处理者),    如果可以处理当前请求,则处理,否则就将该请求交个后继者去处理,从而形成一个职责链。
Request:含有很多属性,表示一个请求。

2、代码实现

需要处理的请求类

public class SchoolRequest {
    // 请求的类型
    private String type;
    // 请求的大概金额
    private float money;
    // ID
    private int id;

    public SchoolRequest(String type, float money, int id) {
        this.type = type;
        this.money = money;
        this.id = id;
    }

    public String getType() {
        return type;
    }

    public float getMoney() {
        return money;
    }

    public int getId() {
        return id;
    }
}

 审批者抽象类

//审批者
public abstract class Approver {

    //聚合,下一个处理的审批者;
    Approver approver;

    //当前审批的部门名字
    String name;

    public Approver(String name) {
        this.name = name;
    }

    //设置下一个审批者到底是谁;
    public void setApprover(Approver approver) {
        this.approver = approver;
    }

    //处理请求的方法
    public abstract void HandlingRequest(SchoolRequest schoolRequest);
}

教导主任审批类 

//教导主任审批
public class DirectorApprover extends Approver {

    public DirectorApprover(String name) {
        super(name);
    }

    @Override
    public void HandlingRequest(SchoolRequest schoolRequest) {
        if(schoolRequest.getMoney() <= 5000){
            System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
            System.out.println("项目ID为" + schoolRequest.getId());
        }else {
            approver.HandlingRequest(schoolRequest);
        }
    }
}

院长审批类 

//院长审批
public class DeanApprover extends Approver {

    public DeanApprover(String name) {
        super(name);
    }

    @Override
    public void HandlingRequest(SchoolRequest schoolRequest) {
        if(schoolRequest.getMoney() <= 5000 && schoolRequest.getMoney() <= 10000){
            System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
            System.out.println("项目ID为" + schoolRequest.getId());
        }else {
            approver.HandlingRequest(schoolRequest);
        }
    }
}

副校长审批类 

//副校长审批
public class VicePresidentApprover extends Approver {

    public VicePresidentApprover(String name) {
        super(name);
    }

    @Override
    public void HandlingRequest(SchoolRequest schoolRequest) {
        if(schoolRequest.getMoney() > 10000 && schoolRequest.getMoney() <= 30000){
            System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
            System.out.println("项目ID为" + schoolRequest.getId());
        }else {
            approver.HandlingRequest(schoolRequest);
        }
    }
}

校长审批类 

//校长审批
public class PresidentApprover extends Approver {

    public PresidentApprover(String name) {
        super(name);
    }

    @Override
    public void HandlingRequest(SchoolRequest schoolRequest) {
        System.out.println(this.name + "能处理这个项目===>" + schoolRequest.getType());
        System.out.println("项目ID为" + schoolRequest.getId());
    }
}

测试

public class Client {
    public static void main(String[] args) {
        //提出请求
        SchoolRequest schoolRequest = new SchoolRequest("采购教学用品", 60000, 1);

        DirectorApprover directorApprover = new DirectorApprover("教导主任");
        DeanApprover deanApprover = new DeanApprover("院长");
        VicePresidentApprover vicePresidentApprover = new VicePresidentApprover("副校长");
        PresidentApprover presidentApprover = new PresidentApprover("校长");

        //设置好下一个处理的人
        directorApprover.setApprover(deanApprover);
        deanApprover.setApprover(vicePresidentApprover);
        vicePresidentApprover.setApprover(presidentApprover);

        //教导主任收到请求时
        directorApprover.HandlingRequest(schoolRequest);
    }
}

结果

校长能处理这个项目===>采购教学用品
项目ID为1

 二、职责链模式在 SpringMVC 框架应用的源码分析

在SpringMVC中DispatcherServlet的HandlerExecutionChain也应用了这一设计模式的思路(可能并不是太典型,这个最后总结):

在doDispatch方法中定义并获取了HandlerExecutionChain的对象,然后调用了applyPreHandle、applyPostHandle方法。

protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
        HttpServletRequest processedRequest = request;
        HandlerExecutionChain mappedHandler = null;
        boolean multipartRequestParsed = false;
 
        WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
 
        try {
            ModelAndView mv = null;
            Exception dispatchException = null;
 
            try {
                processedRequest = checkMultipart(request);
                multipartRequestParsed = (processedRequest != request);
                // 获取该请求的handler,每一个handler实为HandlerExecutionChain,它为一个处理链,负责处理整个请求
                mappedHandler = getHandler(processedRequest);
                if (mappedHandler == null || mappedHandler.getHandler() == null) {
                    noHandlerFound(processedRequest, response);
                    return;
                }
 
                HandlerAdapter ha = getHandlerAdapter(mappedHandler.getHandler());
 
                String method = request.getMethod();
                boolean isGet = "GET".equals(method);
                if (isGet || "HEAD".equals(method)) {
                    long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
                    if (logger.isDebugEnabled()) {
                        logger.debug("Last-Modified value for [" + getRequestUri(request) + "] is: " + lastModified);
                    }
                    if (new ServletWebRequest(request, response).checkNotModified(lastModified) && isGet) {
                        return;
                    }
                }
                // 责任链执行预处理方法,实则是将请求交给注册的请求拦截器执行
                if (!mappedHandler.applyPreHandle(processedRequest, response)) {
                    return;
                }
                // 实际的执行逻辑的部分,也就是你加了@RequestMapping注解的方法
                mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
 
                if (asyncManager.isConcurrentHandlingStarted()) {
                    return;
                }
                applyDefaultViewName(processedRequest, mv);
                // 责任链执行后处理方法,实则是将请求交给注册的请求拦截器执行
                mappedHandler.applyPostHandle(processedRequest, response, mv);
            }
            catch (Exception ex) {
                dispatchException = ex;
            }
            catch (Throwable err) {
                dispatchException = new NestedServletException("Handler dispatch failed", err);
            }
            // 处理返回的结果,触发责任链上注册的拦截器的AfterCompletion方法,其中也用到了HandlerExecutionChain注册的handler来处理错误结果
            processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
        }
        catch (Exception ex) {
            // 触发责任链上注册的拦截器的AfterCompletion方法
            triggerAfterCompletion(processedRequest, response, mappedHandler, ex);
        }
        catch (Throwable err) {
            triggerAfterCompletion(processedRequest, response, mappedHandler,
                    new NestedServletException("Handler processing failed", err));
        }
        finally {
            if (asyncManager.isConcurrentHandlingStarted()) {
                if (mappedHandler != null) {
                    mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
                }
            }
            else {
                if (multipartRequestParsed) {
                    cleanupMultipart(processedRequest);
                }
            }
        }
    }

首先看下HandlerExecutionChain的作用:

public class HandlerExecutionChain {

    private final Object handler;
    private final List<HandlerInterceptor> interceptorList;
    private int interceptorIndex;
}

HandlerExecutionChain持有http请求的处理器,即代码中的handler对象,以及拦截器的数组interceptors,既处理http请求的具体逻辑,又使用拦截器对http请求进行拦截,而此处对于拦截器的调用就应用了责任链模式的思路。

getHandler方法

/**
*  调用HandlerMapping处理器映射器,请求获取Handle处理器
*/
    @Nullable
    protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
        //如果处理器映射器集合不为空
        if (this.handlerMappings != null) {
            Iterator var2 = this.handlerMappings.iterator();
            
            //遍历处理器映射器集合
            while(var2.hasNext()) {
                HandlerMapping mapping = (HandlerMapping)var2.next();
                //调用每个处理器映射器的getHandler()方法,尝试获取处理器对象
                HandlerExecutionChain handler = mapping.getHandler(request);
                //如果处理器对象不为空,说明该处理器映射器获取到了正确的处理器,将其返回
                if (handler != null) {
                    return handler;
                }
            }
        }

        return null;
    }

applyPreHandler方法

    boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
        for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            if (!interceptor.preHandle(request, response, this.handler)) {
                this.triggerAfterCompletion(request, response, (Exception)null);
                return false;
            }
        }

        return true;
    }

此处遍历拦截器的数组,调用拦截器的preHandle方法对请求进行处理,并且只有当本次preHandle处理返回true时,下一个拦截器才会进行执行preHandle方法;如果返回false,就执行triggerAfterCompletion并跳出循环。

总结:为什么开头说不是特别典型的责任链模式,因为此处的拦截器没有包含对另一拦截器的引用,而是通过数组的方式来达到类似的效果。

triggerAfterCompletion方法

   void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
        for(int i = this.interceptorIndex; i >= 0; --i) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);

            try {
                interceptor.afterCompletion(request, response, this.handler, ex);
            } catch (Throwable var7) {
                logger.error("HandlerInterceptor.afterCompletion threw exception", var7);
            }
        }

    }

 此处逻辑类似,只不过这里调用的是拦截器的afterCompletion方法。

applyPostHandle方法

    void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
        for(int i = this.interceptorList.size() - 1; i >= 0; --i) {
            HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
            interceptor.postHandle(request, response, this.handler, mv);
        }

    }

此处逻辑类似,只不过这里调用的是拦截器的postHandle方法。

总结:

  1. 在该doDispatch方法中,使用到了HandlerExecutionChain这个类。
  2. HandlerExecutionChain这个类维护了一个处理器对象,和一个 HandlerInterceptor处理器拦截器的集合,可以向其中注册相应的拦截器,我们称之为拦截器执行链chain。
  3. HandlerExecutionChain 主要负责的是请求拦截器的执行和请求处理,但是他本身不处理请求,只是将请求分配给链上注册处理器执行,这是职责链实现方式,减少职责链本身与处理逻辑之间的耦合,规范了处理流程。

参考文章:责任链模式-以SpringMVC中DispatcherServlet的HandlerExecutionChain为例_一首简单的歌-shining的博客-CSDN博客

三、职责链模式的注意事项和细节

1)将请求和处理分开,实现解耦,提高系统的灵活性

2)简化了对象,使对象不需要知道链的结构

3)性能会受到影响,特别是在链比较长的时候。因此需控制链中最大节点数量,一般通过在 Handler 中设置一个最大节点数量,在 setNext()方法中判断是否已经超过阀值,超过则不允许该链建立,避免出现超长链无意识地破坏系统性能。

4)调试不方便。采用了类似递归的方式,调试时逻辑可能比较复杂。

应用场景

有多个对象可以处理同一个请求时,比如:多级请求、请假/加薪等审批流程、Java Web中Tomcat对 Encoding  的处理、拦截器

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
尚硅谷是一家提供职业教育培训的机构,他们出版了《图解Java设计模式》这本书。 这本书主要介绍了Java设计模式的内容。设计模式是一种在软件设计中常用的解决问题的方法,它提供了一套通用的解决方案,帮助我们在开发过程中更加高效地解决各种问题。 《图解Java设计模式》从实际开发中的场景出发,通过图解的方式,为读者详细介绍了23种常用的设计模式。每一种设计模式都有对应的UML图和实例代码,从而帮助读者理解和应用这些设计模式。 这本书首先介绍了设计模式的基本概念和原则,然后详细介绍了创建型模式、结构型模式和行为型模式。在介绍每一种设计模式时,书中都会提供一个实际的应用场景,并通过图示和代码示例进行详细的讲解,帮助读者更好地理解和掌握这些设计模式。 通过阅读《图解Java设计模式》,读者可以学习到如何利用不同的设计模式解决实际开发中的问题,提高代码的复用性、可维护性和扩展性。这本书适合已经具备一定Java开发经验的读者,对于希望提升自己的设计能力和编码水平的开发者来说,是一本值得推荐的书籍。 总之,《图解Java设计模式》是一本内容丰富、通俗易懂、实用性强的Java设计模式入门书籍,通过阅读并实践书中的内容,读者可以提升自己的软件设计和开发能力。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小鲁蛋儿

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值