关于设计模式:遇到无序多变请求怎么办可以试试责任链模式

90次阅读

共计 7814 个字符,预计需要花费 20 分钟才能阅读完成。

责任链模式(Chain Of Responsibility Design Pattern),也叫做职责链,是将申请的发送和接管解耦,让多个接管对象都有机会解决这个申请。当有申请产生时,可将申请沿着这条链传递,直到有对象解决它为止。

一、责任链模式介绍

其实在日常生活中,有不少应用责任链的场景。比方公司洽购审批流程,须要各个部门领导的批准批准。在责任链模式中,客户端只须要将申请发送到责任链上,毋庸关怀申请的解决细节和传递,申请会主动进行传递。

1.1 责任链模式的构造

责任链模式构造的外围在于引入了一个形象解决类,所以次要蕴含两个局部

  • 一个形象 Handler 类

    • 因为责任链的存在,须要定义下一个 handler 的援用,能力造成一个链条
    • 有了下一个 handler 援用,所以要对援用进行调用和治理,于是须要setNext()getNext() 办法
    • 此外因为不同 handler 解决申请的形式不统一,所以要在其中定义一个形象的申请办法handleRequest()
  • 一系列具体的 Handler 解决类

具体构造大抵如下所示:

  • abstract Handler:形象解决者,定义一个解决申请的接口,外部蕴含形象解决办法和后继具体解决者
  • Handler1、Handler2:具体解决者,具体实现形象解决者的办法,并对申请做一些逻辑解决
  • Client:客户端,应用职责链模式

1.2 职责链模式的实现

依据下面的类图,能够实现如下代码:

/**
 * @description: 形象解决类
 * @date: 2022/4/4
 */
public abstract class Handler {

    private Handler successor;

    public Handler getSuccessor() {return successor;}

    public void setSuccessor(Handler successor) {this.successor = successor;}

    /**
     * 解决申请的形象办法
     * @param request 申请
     */
    public abstract void handleRequest(String request);
}
/**
 * @description: 具体解决者 1
 * @date: 2022/4/4
 */
public class Handler1 extends Handler{

    private String handler;

    public Handler1(String handler) {this.handler = handler;}

    @Override
    public void handleRequest(String request) {if ("handler1".equals(request)) {System.out.println("具体解决者 handler1 进行申请解决");
        } else {if (getSuccessor() != null) {
                // 如果指向下一个具体解决者
                getSuccessor().handleRequest(request);
            } else {System.out.println("没有解决者进行解决");
            }
        }
    }
}
/**
 * @description: 具体解决者 2
 * @date: 2022/4/4
 */
public class Handler2 extends Handler{

    private String handler;

    public Handler2(String handler) {this.handler = handler;}

    @Override
    public void handleRequest(String request) {if ("handler2".equals(request)) {System.out.println("具体解决者 handler2 进行申请解决");
        } else {if (getSuccessor() != null) {getSuccessor().handleRequest(request);
            } else {System.out.println("申请没有被任何解决者解决");
            }
        }
    }
}
/**
 * @description: 客户端类
 * @date: 2022/4/4
 */
public class Client {public static void main(String[] args) {Handler handler1 = new Handler1("handler1");
        Handler handler2 = new Handler2("handler2");
        handler1.setSuccessor(handler2);
        handler1.handleRequest("handler1");
        handler1.handleRequest("handler2");

    }
}

测试后果:

具体解决者 handler1 进行申请解决
具体解决者 handler2 进行申请解决

二、责任链模式的利用场景

责任链实用的利用场景有:

  1. 当程序须要应用不同形式来解决不同品种的申请,而且各个申请类型和顺

职责链模式最常见的利用就是用来开发各种框架的过滤器和拦截器,比方 Spring Interceptor 和 Servlet Filter

2.1 在 Servlet Filter 中的利用

Filter 能够实现对 HTTP 申请的过滤性能,比方鉴权、限流、记录日志、验证参数等等。比方一些 Servlet 容器(TomCat、Jetty 等)就反对 Filter 的过滤性能。以 TomCat 为例:

所以当 Servlet 申请到来时,首先会通过 Filter 解决,最初再达到 Servlet 实例。我这里选取的 TomCat 版本是 SpringBoot 自带的 9.0,先来看看FilterChain 的接口:

public interface FilterChain {
    //Filter 具体实现
    void doFilter(ServletRequest var1, ServletResponse var2) throws IOException, ServletException;
}

ApplicationFilterChain是责任链模式的具体实现类:

public final class ApplicationFilterChain implements FilterChain {private ApplicationFilterConfig[] filters = new ApplicationFilterConfig[0]; //Filter 配置数组
    private int pos = 0; // 执行 Filter 的序号
    private int n = 0;     // 目前 Filter 的个数
    private Servlet servlet = null;

    public ApplicationFilterChain() {}
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response) throws IOException, ServletException {
        //Filter 具体实现
        //...
    }
    
    public static ServletRequest getLastServicedRequest() {return (ServletRequest)lastServicedRequest.get();}

    public static ServletResponse getLastServicedResponse() {return (ServletResponse)lastServicedResponse.get();}

    void addFilter(ApplicationFilterConfig filterConfig) {ApplicationFilterConfig[] newFilters = this.filters;
        int var3 = newFilters.length;

        for(int var4 = 0; var4 < var3; ++var4) {ApplicationFilterConfig filter = newFilters[var4];
            if (filter == filterConfig) {return;}
        }
        // 减少 Filter
        if (this.n == this.filters.length) {newFilters = new ApplicationFilterConfig[this.n + 10];
            System.arraycopy(this.filters, 0, newFilters, 0, this.n);
            this.filters = newFilters;
        }

        this.filters[this.n++] = filterConfig;
    }
}

2.2 在 Spring Interceptor 中的利用

和 Servlet Filter 相似,在 Spring 中也有对应的过滤器 Interceptor。它是由 Spring MVC 框架来实现,借一张来自《设计模式之美》的图片来阐明:

客户端发送申请,首先会通过 Servlet Filter,而后再通过 Spring Interceptor,最初再达到具体的业务中。

和 Filter 一样,Interceptor 中也是基于责任链模式来实现的,与之绝对的 HandlerInterceptor 是形象解决接口:

public interface HandlerInterceptor {default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {return true;}

    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { }

    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {}}

会有各种具体解决类的实现:

此外在其余框架中也存在着职责链模式的应用,比方 Dubbo Filter、Netty ChannelPipeline 等等

三、责任链模式实战

模仿在 618 大促期间的业务零碎上线审批流程场景:

像是这些⼀线电商类的互联⽹公司,阿⾥、京东、拼多多等,在 618 期间都会做⼀些经营流动场景以及 提供的扩容备战,就像过年期间百度的红包⼀样。然而所有开发的这些零碎都须要陆续的上线,因为临 近 618 有时候也有⼀些紧急的调整的须要上线,但为了保障线上零碎的稳定性是尽可能的缩小上线的,也会相应的加强审批⼒度。就像⼀级响应、⼆级响应⼀样。

⽽这审批的过程在随着特定工夫点会减少不同级别的负责⼈加⼊,每个⼈就像责任链模式中的每⼀个核 ⼼点。对于研发并不需要关⼼具体的审批流程解决细节,只须要晓得这个上线更严格,级别也更 ⾼,但对于研发⼈员来说同样是点击雷同的提审按钮,期待审核。

应用责任链模式能够将各个服务模块依照一、二、三级进行拆散,每个级别能够像 Filter 一样用 Successor 下一个级别的办法进行调用。具体结构图如下(来自《重学 Java 设计模式》)

具体代码构造

│——AuthInfo.java
│——AuthLink.java
│
├─business
│     AuthService.java
│
└─impl
      Level1AuthLink.java
      Level2AuthLink.java
      Level3AuthLink.java

实现代码:

/**
 * @description: 链路形象审批
 * @date: 2022/4/4
 */
public abstract class AuthLink {

    /** 工夫格式化 **/
    protected SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
    /** 级别人员 ID**/
    protected String levelUserId;
    /** 级别人员姓名 **/
    protected String levelUserName;
    /** 下一个链路 **/
    private AuthLink next;

    public AuthLink(String levelUserId, String levelUserName) {
        this.levelUserId = levelUserId;
        this.levelUserName = levelUserName;
    }

    public AuthLink next() {return next;}

    public AuthLink appendNext(AuthLink next) {
        this.next = next;
        return this;
    }

    /** 每个具体解决者必须实现的办法 **/
    public abstract AuthInfo doAuth(String uId, String orderId, Date authDate);
}
/**
 * @description: 责任链中返回对象的定义
 * @date: 2022/4/4
 */
public class AuthInfo {

    private String code;
    private String info = " ";

    public AuthInfo(String code, String... infos) { //... 示意可变长参数,能够传入多个参数
        this.code = code;
        for (String s : infos) {this.info = this.info.concat(s);
        }
    }

    public String getCode() {return code;}

    public void setCode(String code) {this.code = code;}

    public String getInfo() {return info;}

    public void setInfo(String info) {this.info = info;}
}
/**
 * @description: 一级审核人
 * @date: 2022/4/4
 */
public class Level1AuthLink extends AuthLink {public Level1AuthLink(String levelUserId, String levelUserName) {super(levelUserId, levelUserName);
    }

    @Override
    public AuthInfo doAuth(String uId, String orderId, Date authDate) {Date date = AuthService.queryAuthInfo(levelUserId, orderId);
        if (null == date) {return new AuthInfo("0001", "单号", orderId, "状态:一级审批负责人", levelUserName);
        }
        AuthLink next = super.next();
        if (null == next) {return new AuthInfo("0000", "单号", orderId, "状态:一级审批负责人", "工夫:", f.format(date), "审批人:", levelUserName);
        }
        return next.doAuth(uId, orderId, authDate);
    }
}
/**
 * @description: 测试类
 * @date: 2022/4/5
 */
public class ApiTest {private Logger logger = LoggerFactory.getLogger(ApiTest.class);

    @Test
    public void test_AuthLink() throws ParseException {AuthLink authLink = new Level3AuthLink("1000013", "王工")
                .appendNext(new Level2AuthLink("1000012", "张经理"))
                .appendNext(new Level3AuthLink("1000011", "赵总裁"));

        logger.info("测试后果:{}", JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));

        AuthService.auth("1000013", "100099800423123");
        logger.info("测试后果:{}", "模仿二级审批,王工");
        logger.info("测试后果:{}",JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));

        AuthService.auth("1000012", "100099800423123");
        logger.info("测试后果:{}", "模仿二级负责人审批,张经理");
        logger.info("测试后果:{}", JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));

        AuthService.auth("1000011", "100099800423123");
        logger.info("测试后果:{}", "模仿二级负责人审批,赵总裁");
        logger.info("测试后果:{}", JSON.toJSONString(authLink.doAuth("ethan", "100099800423123", new Date())));

    }
}

最初的测试后果:

10:45:14.496 [main] INFO  ApiTest - 测试后果:{"code":"0001","info":"单号:100099800423123 状态:待三级审批 王工"}
10:45:14.500 [main] INFO  ApiTest - 测试后果:模仿二级审批,王工
10:45:14.500 [main] INFO  ApiTest - 测试后果:{"code":"0001","info":"单号:100099800423123 状态:待三级审批 赵总裁"}
10:45:14.500 [main] INFO  ApiTest - 测试后果:模仿二级负责人审批,张经理
10:45:14.500 [main] INFO  ApiTest - 测试后果:{"code":"0001","info":"单号:100099800423123 状态:待三级审批 赵总裁"}
10:45:14.500 [main] INFO  ApiTest - 测试后果:模仿二级负责人审批,赵总裁
10:45:14.500 [main] INFO  ApiTest - 测试后果:{"code":"0000","info":"单号:100099800423123 状态:三级审批实现 工夫:2022-04-05 10:45:14 审批人:赵总裁"}

参考资料

《设计模式之美》

http://c.biancheng.net/view/4024.html

《重学 Java 设计模式》

正文完
 0