永久免费网站京津冀协同发展规划纲要

张小明 2026/1/3 7:02:27
永久免费网站,京津冀协同发展规划纲要,网站 系统 区别,什么公司在百度做网站责任链模式#xff0c;简而言之#xff0c;就是将多个操作组装成 一条链路进行处理。请求在链路上传递#xff0c;链路上 的每一个节点就是一个处理器#xff0c;每个处理器都可 以对请求进行处理#xff0c;或者传递给链路上的下一个 处理器处理。 ‍ ‍ 应用场景 …责任链模式简而言之就是将多个操作组装成一条链路进行处理。请求在链路上传递链路上的每一个节点就是一个处理器每个处理器都可以对请求进行处理或者传递给链路上的下一个处理器处理。‍‍应用场景责任链模式的应用场景在实际工作中通常有如下两种应用场景。操作需要经过一系列的校验通过校验后才执行某些操作。工作流。企业中通常会制定很多工作流程一级一级的去处理任务。下面通过两个案例来学习一下责任链模式。案例一创建商品多级校验场景以创建商品为例假设商品创建逻辑分为以下三步完成①创建商品、②校验商品参数、③保存商品。第②步校验商品又分为多种情况的校验必填字段校验、规格校验、价格校验、库存校验等等。这些检验逻辑像一个流水线要想创建出一个商品必须通过这些校验。如下流程图所示伪代码如下创建商品步骤需要经过一系列的参数校验如果参数校验失败直接返回失败的结果通过所有的参数校验后最终保存商品信息。如上代码看起来似乎没什么问题它非常工整而且代码逻辑很清晰。PS我没有把所有的校验代码都罗列在一个方法里那样更能产生对比性但我觉得抽象并分离单一职责的函数应该是每个程序员最基本的规范但是随着业务需求不断地叠加相关的校验逻辑也越来越多新的功能使代码越来越臃肿可维护性较差。更糟糕的是这些校验组件不可复用当你有其他需求也需要用到一些校验时你又变成了CtrlC , CtrlV程序员系统的维护成本也越来越高。如下图所示伪代码同上这里就不赘述了。终于有一天你忍无可忍了决定重构这段代码。使用责任链模式优化创建商品的每个校验步骤都可以作为一个单独的处理器抽离为一个单独的类便于复用。这些处理器形成一条链式调用请求在处理器链上传递如果校验条件不通过则处理器不再向下传递请求直接返回错误信息若所有的处理器都通过检验则执行保存商品步骤。案例一实战责任链模式实现创建商品校验UML图一览众山小AbstractCheckHandler表示处理器抽象类负责抽象处理器行为。其有3个子类分别是NullValueCheckHandler空值校验处理器PriceCheckHandler价格校验处理StockCheckHandler库存校验处理器AbstractCheckHandler 抽象类中handle()定义了处理器的抽象方法其子类需要重写handle()方法以实现特殊的处理器校验逻辑protected ProductCheckHandlerConfig config 是处理器的动态配置类使用protected声明每个子类处理器都持有该对象。该对象用于声明当前处理器、以及当前处理器的下一个处理器nextHandler另外也可以配置一些特殊属性比如说接口降级配置、超时时间配置等。AbstractCheckHandler nextHandler 是当前处理器持有的下一个处理器的引用当前处理器执行完毕时便调用nextHandler执行下一处理器的handle()校验方法protected Result next()是抽象类中定义的执行下一个处理器的方法使用protected声明每个子类处理器都持有该对象。当子类处理器执行完毕(通过)时调用父类的方法执行下一个处理器nextHandler。HandlerClient 是执行处理器链路的客户端HandlerClient.executeChain()方法负责发起整个链路调用并接收处理器链路的返回值。撸起袖子开始撸代码吧 ~商品参数对象保存商品的入参ProductVO是创建商品的参数对象包含商品的基础信息。并且其作为责任链模式中多个处理器的入参多个处理器都以ProductVO为入参进行特定的逻辑处理。实际业务中商品对象特别复杂。咱们化繁为简简化商品参数如下/** * 商品对象 */ Data Builder publicclass ProductVO { /** * 商品SKU唯一 */ private Long skuId; /** * 商品名称 */ private String skuName; /** * 商品图片路径 */ private String Path; /** * 价格 */ private BigDecimal price; /** * 库存 */ private Integer stock; }抽象类处理器抽象行为子类共有属性、方法AbstractCheckHandler处理器抽象类并使用Component注解注册为由Spring管理的Bean对象这样做的好处是我们可以轻松的使用Spring来管理这些处理器Bean。/** * 抽象类处理器 */ Component publicabstractclass AbstractCheckHandler { /** * 当前处理器持有下一个处理器的引用 */ Getter Setter protected AbstractCheckHandler nextHandler; /** * 处理器配置 */ Setter Getter protected ProductCheckHandlerConfig config; /** * 处理器执行方法 * param param * return */ public abstract Result handle(ProductVO param); /** * 链路传递 * param param * return */ protected Result next(ProductVO param) { //下一个链路没有处理器了直接返回 if (Objects.isNull(nextHandler)) { return Result.success(); } //执行下一个处理器 return nextHandler.handle(param); } }在AbstractCheckHandler抽象类处理器中使用protected声明子类可见的属性和方法。使用 Component注解声明其为Spring的Bean对象这样做的好处是可以利用Spring轻松管理所有的子类下面会看到如何使用。抽象类的属性和方法说明如下public abstract Result handle()表示抽象的校验方法每个处理器都应该继承AbstractCheckHandler抽象类处理器并重写其handle方法各个处理器从而实现特殊的校验逻辑实际上就是多态的思想。protected ProductCheckHandlerConfig config表示每个处理器的动态配置类可以通过“配置中心”动态修改该配置实现处理器的“动态编排”和“顺序控制”。配置类中可以配置处理器的名称、下一个处理器、以及处理器是否降级等属性。protected AbstractCheckHandler nextHandler表示当前处理器持有下一个处理器的引用如果当前处理器handle()校验方法执行完毕则执行下一个处理器nextHandler的handle()校验方法执行校验逻辑。protected Result next(ProductVO param)此方法用于处理器链路传递子类处理器执行完毕后调用父类的next()方法执行在config 配置的链路上的下一个处理器如果所有处理器都执行完毕了就返回结果了。ProductCheckHandlerConfig配置类 :/** * 处理器配置类 */ AllArgsConstructor Data public class ProductCheckHandlerConfig { /** * 处理器Bean名称 */ private String handler; /** * 下一个处理器 */ private ProductCheckHandlerConfig next; /** * 是否降级 */ private Boolean down Boolean.FALSE; }子类处理器处理特有的校验逻辑AbstractCheckHandler抽象类处理器有3个子类分别是NullValueCheckHandler空值校验处理器PriceCheckHandler价格校验处理StockCheckHandler库存校验处理器各个处理器继承AbstractCheckHandler抽象类处理器并重写其handle()处理方法以实现特有的校验逻辑。NullValueCheckHandler空值校验处理器。针对性校验创建商品中必填的参数。如果校验未通过则返回错误码ErrorCode责任链在此截断(停止)创建商品返回被校验住的错误信息。注意代码中的降级配置super.getConfig().getDown()是获取AbstractCheckHandler处理器对象中保存的配置信息如果处理器配置了降级则跳过该处理器调用super.next()执行下一个处理器逻辑。同样使用Component注册为由Spring管理的Bean对象/** * 空值校验处理器 */ Component publicclass NullValueCheckHandler extends AbstractCheckHandler{ Override public Result handle(ProductVO param) { System.out.println(空值校验 Handler 开始...); //降级如果配置了降级则跳过此处理器执行下一个处理器 if (super.getConfig().getDown()) { System.out.println(空值校验 Handler 已降级跳过空值校验 Handler...); returnsuper.next(param); } //参数必填校验 if (Objects.isNull(param)) { return Result.failure(ErrorCode.PARAM_NULL_ERROR); } //SkuId商品主键参数必填校验 if (Objects.isNull(param.getSkuId())) { return Result.failure(ErrorCode.PARAM_SKU_NULL_ERROR); } //Price价格参数必填校验 if (Objects.isNull(param.getPrice())) { return Result.failure(ErrorCode.PARAM_PRICE_NULL_ERROR); } //Stock库存参数必填校验 if (Objects.isNull(param.getStock())) { return Result.failure(ErrorCode.PARAM_STOCK_NULL_ERROR); } System.out.println(空值校验 Handler 通过...); //执行下一个处理器 returnsuper.next(param); } }PriceCheckHandler价格校验处理。针对创建商品的价格参数进行校验。这里只是做了简单的判断价格0的校验实际业务中比较复杂比如“价格门”这些防范措施等。/** * 价格校验处理器 */ Component publicclass PriceCheckHandler extends AbstractCheckHandler{ Override public Result handle(ProductVO param) { System.out.println(价格校验 Handler 开始...); //非法价格校验 boolean illegalPrice param.getPrice().compareTo(BigDecimal.ZERO) 0; if (illegalPrice) { return Result.failure(ErrorCode.PARAM_PRICE_ILLEGAL_ERROR); } //其他校验逻辑... System.out.println(价格校验 Handler 通过...); //执行下一个处理器 returnsuper.next(param); } }StockCheckHandler库存校验处理器。针对创建商品的库存参数进行校验。/** * 库存校验处理器 */ Component publicclass StockCheckHandler extends AbstractCheckHandler{ Override public Result handle(ProductVO param) { System.out.println(库存校验 Handler 开始...); //非法库存校验 boolean illegalStock param.getStock() 0; if (illegalStock) { return Result.failure(ErrorCode.PARAM_STOCK_ILLEGAL_ERROR); } //其他校验逻辑.. System.out.println(库存校验 Handler 通过...); //执行下一个处理器 returnsuper.next(param); } }客户端执行处理器链路HandlerClient客户端类负责发起整个处理器链路的执行通过executeChain()方法。如果处理器链路返回错误信息即校验未通过则整个链路截断停止返回相应的错误信息。public class HandlerClient { public static Result executeChain(AbstractCheckHandler handler, ProductVO param) { //执行处理器 Result handlerResult handler.handle(param); if (!handlerResult.isSuccess()) { System.out.println(HandlerClient 责任链执行失败返回 handlerResult.toString()); return handlerResult; } return Result.success(); } }以上责任链模式相关的类已经创建好了。接下来就可以创建商品了。创建商品抽象步骤化繁为简createProduct()创建商品方法抽象为2个步骤①参数校验、②创建商品。参数校验使用责任链模式进行校验包含空值校验、价格校验、库存校验等等只有链上的所有处理器均校验通过才调用saveProduct()创建商品方法否则返回校验错误信息。在createProduct()创建商品方法中通过责任链模式我们将校验逻辑进行解耦。createProduct()创建商品方法中不需要关注都要经过哪些校验处理器以及校验处理器的细节。/** * 创建商品 * return */ Test public Result createProduct(ProductVO param) { //参数校验使用责任链模式 Result paramCheckResult this.paramCheck(param); if (!paramCheckResult.isSuccess()) { return paramCheckResult; } //创建商品 return this.saveProduct(param); }参数校验责任链模式参数校验paramCheck()方法使用责任链模式进行参数校验方法内没有声明具体都有哪些校验具体有哪些参数校验逻辑是通过多个处理器链传递的。如下/** * 参数校验责任链模式 * param param * return */ private Result paramCheck(ProductVO param) { //获取处理器配置通常配置使用统一配置中心存储支持动态变更 ProductCheckHandlerConfig handlerConfig this.getHandlerConfigFile(); //获取处理器 AbstractCheckHandler handler this.getHandler(handlerConfig); //责任链执行处理器链路 Result executeChainResult HandlerClient.executeChain(handler, param); if (!executeChainResult.isSuccess()) { System.out.println(创建商品 失败...); return executeChainResult; } //处理器链路全部成功 return Result.success(); }paramCheck()方法步骤说明如下 步骤1获取处理器配置。通过getHandlerConfigFile()方法获取处理器配置类对象配置类保存了链上各个处理器的上下级节点配置支持流程编排、动态扩展。通常配置是通过Ducc(京东自研的配置中心)、Nacos(阿里开源的配置中心)等配置中心存储的支持动态变更、实时生效。基于此我们便可以实现校验处理器的编排、以及动态扩展了。我这里没有使用配置中心存储处理器链路的配置而是使用JSON串的形式去模拟配置大家感兴趣的可以自行实现。/** * 获取处理器配置通常配置使用统一配置中心存储支持动态变更 * return */ private ProductCheckHandlerConfig getHandlerConfigFile() { //配置中心存储的配置 String configJson {\handler\:\nullValueCheckHandler\,\down\:true,\next\:{\handler\:\priceCheckHandler\,\next\:{\handler\:\stockCheckHandler\,\next\:null}}}; //转成Config对象 ProductCheckHandlerConfig handlerConfig JSON.parseObject(configJson, ProductCheckHandlerConfig.class); return handlerConfig; }ConfigJson存储的处理器链路配置JSON串在代码中可能不便于观看我们可以使用json.cn等格式化看一下如下配置的整个调用链路规则特别清晰。getHandlerConfigFile()类获到配置类的结构如下可以看到就是把在配置中心储存的配置规则转换成配置类ProductCheckHandlerConfig对象用于程序处理。注意此时配置类中存储的仅仅是处理器Spring Bean的name而已并非实际处理器对象。接下来通过配置类获取实际要执行的处理器。 步骤2根据配置获取处理器。上面步骤1通过getHandlerConfigFile()方法获取到处理器链路配置规则后再调用getHandler()获取处理器。getHandler()参数是如上ConfigJson配置的规则即步骤1转换成的ProductCheckHandlerConfig对象根据ProductCheckHandlerConfig配置规则转换成处理器链路对象。代码如下* 使用Spring注入:所有继承了AbstractCheckHandler抽象类的Spring Bean都会注入进来。Map的Key对应Bean的name,Value是name对应相应的Bean */ Resource private MapString, AbstractCheckHandler handlerMap; /** * 获取处理器 * param config * return */ private AbstractCheckHandler getHandler (ProductCheckHandlerConfig config) { //配置检查没有配置处理器链路则不执行校验逻辑 if (Objects.isNull(config)) { returnnull; } //配置错误 String handler config.getHandler(); if (StringUtils.isBlank(handler)) { returnnull; } //配置了不存在的处理器 AbstractCheckHandler abstractCheckHandler handlerMap.get(config.getHandler()); if (Objects.isNull(abstractCheckHandler)) { returnnull; } //处理器设置配置Config abstractCheckHandler.setConfig(config); //递归设置链路处理器 abstractCheckHandler.setNextHandler(this.getHandler(config.getNext())); return abstractCheckHandler; } 步骤2-1配置检查。代码14~27行进行了配置的一些检查操作。如果配置错误则获取不到对应的处理器。代码23行handlerMap.get(config.getHandler())是从所有处理器映射Map中获取到对应的处理器Spring Bean。注意第5行代码handlerMap存储了所有的处理器映射是通过Spring Resource注解注入进来的。注入的规则是所有继承了AbstractCheckHandler抽象类它是Spring管理的Bean的子类子类也是Spring管理的Bean都会注入进来。注入进来的handlerMap中 Map的Key对应Bean的nameValue是name对应的Bean实例也就是实际的处理器这里指空值校验处理器、价格校验处理器、库存校验处理器。如下这样根据配置ConfigJson 步骤1获取处理器配置中handler:priceCheckHandler的配置使用handlerMap.get(config.getHandler())便可以获取到对应的处理器Spring Bean对象了。 步骤2-2保存处理器规则。代码29行将配置规则保存到对应的处理器中abstractCheckHandler.setConfig(config)子类处理器就持有了配置的规则。 步骤2-3递归设置处理器链路。代码32行递归设置链路上的处理器。//递归设置链路处理器 abstractCheckHandler.setNextHandler(this.getHandler(config.getNext()));这一步可能不太好理解结合ConfigJson配置的规则来看似乎就很很容易理解了。由上而下NullValueCheckHandler空值校验处理器通过setNextHandler()方法设置自己持有的下一节点的处理器也就是价格处理器PriceCheckHandler。接着PriceCheckHandler价格处理器同样需要经过步骤2-1配置检查、步骤2-2保存配置规则并且最重要的是它也需要设置下一节点的处理器StockCheckHandler库存校验处理器。StockCheckHandler库存校验处理器也一样同样需要经过步骤2-1配置检查、步骤2-2保存配置规则但请注意StockCheckHandler的配置它的next规则配置了null这表示它下面没有任何处理器要执行了它就是整个链路上的最后一个处理节点。通过递归调用getHandler()获取处理器方法就将整个处理器链路对象串联起来了。如下友情提示递归虽香但使用递归一定要注意截断递归的条件处理否则可能造成死循环哦实际上getHandler()获取处理器对象的代码就是把在配置中心配置的规则ConfigJson转换成配置类ProductCheckHandlerConfig对象再根据配置类对象转换成实际的处理器对象这个处理器对象持有整个链路的调用顺序。 步骤3客户端执行调用链路。public class HandlerClient { public static Result executeChain(AbstractCheckHandler handler, ProductVO param) { //执行处理器 Result handlerResult handler.handle(param); if (!handlerResult.isSuccess()) { System.out.println(HandlerClient 责任链执行失败返回 handlerResult.toString()); return handlerResult; } return Result.success(); } }getHandler()获取完处理器后整个调用链路的执行顺序也就确定了此时客户端该干活了HandlerClient.executeChain(handler, param)方法是HandlerClient客户端类执行处理器整个调用链路的并接收处理器链路的返回值。executeChain()通过AbstractCheckHandler.handle()触发整个链路处理器顺序执行如果某个处理器校验没有通过!handlerResult.isSuccess()则返回错误信息所有处理器都校验通过则返回正确信息Result.success()。总结串联方法调用流程基于以上再通过流程图来回顾一下整个调用流程。测试代码执行结果场景1创建商品参数中有空值如下skuId参数为null链路被空值处理器截断返回错误信息//创建商品参数 ProductVO param ProductVO.builder() .skuId(null).skuName(华为手机).Path(http://...) .price(new BigDecimal(1)) .stock(1) .build();测试结果场景2创建商品价格参数异常如下price参数被价格处理器截断返回错误信息ProductVO param ProductVO.builder() .skuId(1L).skuName(华为手机).Path(http://...) .price(new BigDecimal(-999)) .stock(1) .build();测试结果场景 3创建商品库存参数异常如下stock参数被库存处理器截断返回错误信息。//创建商品参数模拟用户传入 ProductVO param ProductVO.builder() .skuId(1L).skuName(华为手机).Path(http://...) .price(new BigDecimal(1)) .stock(-999) .build();测试结果场景4创建商品所有处理器校验通过保存商品。![15](C:\Users\18796\Desktop\文章\15.png)![15](C:\Users\18796\Desktop\文章\15.png)![15](C:\Users\18796\Desktop\文章\15.png)![15](C:\Users\18796\Desktop\文章\15.png)//创建商品参数模拟用户传入 ProductVO param ProductVO.builder() .skuId(1L).skuName(华为手机).Path(http://...) .price(new BigDecimal(999)) .stock(1).build();测试结果案例二工作流费用报销审核流程同事小贾最近刚出差回来她迫不及待的就提交了费用报销的流程。根据金额不同分为以下几种审核流程。报销金额低于1000元三级部门管理者审批即可1000到5000元除了三级部门管理者审批还需要二级部门管理者审批而5000到10000元还需要一级部门管理者审批。即有以下几种情况小贾需报销500元三级部门管理者审批即可。小贾需报销2500元三级部门管理者审批通过后还需要二级部门管理者审批二级部门管理者审批通过后才完成报销审批流程。小贾需报销7500元三级管理者审批通过后并且二级管理者审批通过后流程流转到一级部门管理者进行审批一级管理者审批通过后即完成了报销流程。UML图AbstractFlowHandler作为处理器抽象类抽象了approve()审核方法一级、二级、三级部门管理者处理器继承了抽象类并重写其approve()审核方法从而实现特有的审核逻辑。配置类如下所示每层的处理器都要配置审核人、价格审核规则审核的最大、最小金额、下一级处理人。配置规则是可以动态变更的如果三级部门管理者可以审核的金额增加到2000元修改一下配置即可动态生效。
版权声明:本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!

浙江学院网站建设营销手段有哪些方式

我们在往期内容里讨论过了绘制声子声学支的问题 欢迎讨论:如何正确绘制声子谱声学支 这里非常感谢 云里悟理不能自理 和 振振有声子 两个公众号的运营者对前期相关问题的探讨。 自VASP6.3.2版开始中更新了对于声子色散计算的功能,可以不再需要PHONOPY即…

张小明 2026/1/1 16:16:06 网站建设

网站优化的基本思想与原则合肥网站营销推广

企业级云服务器部署中,RHEL系(如 RHEL、Rocky Linux、AlmaLinux)通常更适合作为首选,但需结合具体场景权衡;Debian/Ubuntu LTS 在特定领域(如云原生、开发友好性、成本敏感型场景)同样具备强大竞…

张小明 2026/1/2 3:21:40 网站建设

网站怎么创建论坛郑州seo优化外包热狗网

文本摘要技术实战:3步解决信息过载难题 【免费下载链接】DeepPavlov An open source library for deep learning end-to-end dialog systems and chatbots. 项目地址: https://gitcode.com/gh_mirrors/de/DeepPavlov 你是否曾在海量文档中迷失方向&#xff1…

张小明 2026/1/1 19:42:17 网站建设

公司网站不备案和备案有什么区别安卓开发为什么不火了

Dify如何避免生成误导性的医疗建议? 在AI日益渗透医疗健康领域的今天,一个看似智能的问答系统如果给出“糖尿病患者可以随意吃香蕉”这样的建议,后果可能不堪设想。大语言模型(LLM)虽然具备强大的自然语言理解与生成能…

张小明 2026/1/1 17:36:47 网站建设

网站备份还原08 iis创建网站

在当今数字化转型浪潮中,企业级后台管理系统已成为各类业务系统的核心支撑。RuoYi-Vue3作为基于最新技术栈打造的开源项目,完美融合了Vue3的响应式特性和Spring Boot的稳定架构,为开发者提供了一站式的快速开发解决方案。 【免费下载链接】Ru…

张小明 2026/1/1 7:45:06 网站建设

如何通过外链提高网站权重com网站怎么注册

Hikari-LLVM15终极指南:5个实战场景掌握代码混淆技术 【免费下载链接】Hikari-LLVM15 项目地址: https://gitcode.com/GitHub_Trending/hi/Hikari-LLVM15 在当今数字化时代,保护代码安全已成为开发者面临的重要挑战。Hikari-LLVM15作为基于LLVM的…

张小明 2026/1/2 21:35:58 网站建设