结合JDK学习设计模式-—行为型设计模式——责任链模式

简单地介绍:

责任链( Chain Of Responsibility
 

使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这

条链发送该请求,直到有一个对象处理它为止。

没有使用时的问题:

在介绍这个设计模式之前,先看看不使用这个模式,我们的代码会是什么样子的.

    public static void main(String[] args) {
        LoginRequest request = new LoginRequest("age","年龄校验");
        
    }
    
    public void checkLoginParam(LoginRequest request){
        if ("name".equals(request.getRequestType())){
            // 姓名的检验逻辑
        }else if ("age".equals(request.getRequestType())){
            // 年龄的校验逻辑
        }
        
        //其他的校验逻辑...............
    }

很容易发现 代码会随着后期校验逻辑的增加 越来越长,越复杂。耦合性很高,而且新增校验逻辑需要修改以前的代码判断分支,也违背了单一职责原则和开闭原则。

使用后的效果:

如何解决这个复杂校验逻辑,还能满足设计原则呢? 

推荐使用 责任链模式,当然,责任链模式的实现方法很多

javax.servlet.Filter#doFilter 使用 过滤器数组 移动数组索引实现 调用下一个过滤器  (核心类 ApplicationFilterChain)

我先采用最简单的嵌套构造的方式来实现:

先看下类图,有个总体的认知

  • 核心 任务处理父类

  • LoginHandler :定义处理请求的接口,并且实现后继链(handler)
public abstract class LoginHandler {
    protected LoginHandler handler;

    public LoginHandler(LoginHandler handler){
        this.handler = handler;
    }

    protected abstract void handlerLoginRequest(LoginRequest request);
}

具体的处理器类:

1. 年龄校验逻辑

public class LoginAgeHandler extends LoginHandler {

    public LoginAgeHandler(LoginHandler handler){
        super(handler);
    }

    @Override
    protected void handlerLoginRequest(LoginRequest request) {
        if ("age".equals(request.getRequestType())){
            System.out.println("LoginAgeHandler----》 " + request.getTaskName());
            return;
        }

        if (null != handler){
            handler.handlerLoginRequest(request);
        }
    }
}

2. 姓名校验逻辑: 

public class LoginNameHandler extends LoginHandler {

    public LoginNameHandler(LoginHandler handler){
        super(handler);
    }

    /**
     *  处理完成自己的逻辑后 判断是否需要交给下一个处理器来处理
     * @param request
     */
    @Override
    protected void handlerLoginRequest(LoginRequest request) {
        if ("name".equals(request.getRequestType())){
           // query user from db, if exist execute next stop
            System.out.println("LoginNameHandler--》" + request.getTaskName());
        }

        // 交给下一个处理器处理 请求任务
        if (null != handler){
            handler.handlerLoginRequest(request);
        }
    }
}

待处理的任务类:

public class LoginRequest {
    private String requestType;
    private String taskName;

    public LoginRequest(String requestType, String taskName) {
        this.requestType = requestType;
        this.taskName = taskName;
    }

    public String getRequestType() {
        return requestType;
    }

    public String getTaskName() {
        return taskName;
    }
}

最后,我们做一下调用测试:

package com.cheri.designpattern.cases.action;

/**
 *
 * 嵌套过滤器,内部依次判断是否存在 执行过滤器
 * @author Aaron Du
 * @version V1.0
 * @date 2020/5/1 15:08
 **/
public class Client {

    public static void main(String[] args) {
        LoginRequest request1 = new LoginRequest("name","用户名检查");
        LoginRequest request2 = new LoginRequest("age","年龄检查");


        LoginHandler ageHandler = new LoginAgeHandler(null);
        LoginHandler nameHandler =  new LoginNameHandler(ageHandler);

        nameHandler.handlerLoginRequest(request1);
        nameHandler.handlerLoginRequest(request2);


    }
}

可以清楚的看到,对应处理器只处理自己负责的处理逻辑。

我们看JDK如何使用责任链模式的:

一般我们使用一个过滤器时都是如下处理:实现Filter接口重写doFilter方法

public class MyFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // 自己过滤器处理逻辑

        // 调用下一个过滤器
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

在Tomcat容器中,会将所有的过滤器加载到  ApplicationFilterChain中的 

private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]数组中

 下面是添加过滤器到数组的方法:

当我们调用 

chain.doFilter(request,response);来调用下一个过滤器时,内部会调用

ApplicationFilterChain的doFilter方法

我们会看到,内部会通过数组索引的递增来逐个调用下一个过滤器,实现过滤器逐个调用的效果。这个是过滤器Filter对

责任链模式的实现方法。

总结:1.要有待处理的任务对象。

             2.要有统一的处理器基类 且 基类中要维护任务和一个抽象的处理方法,不同的子类都实现不同的处理逻辑。

             3. 执行链的维护可以使用数据也可以采用构造嵌套的方式

猜你喜欢

转载自blog.csdn.net/Coder_Boy_/article/details/105879305
今日推荐