全国免费咨询:

13245491521

VR图标白色 VR图标黑色
X

中高端软件定制开发服务商

与我们取得联系

13245491521     13245491521

2024-07-27_使用责任链模式重构计费

您的位置:首页 >> 新闻 >> 行业资讯

使用责任链模式重构计费 什么是计费?计费是结算系统的核心业务,主要承担各业务系统推送过来的计费需求,是收单流程的重要一环。 业务系统推送业务单据到结算系统以后,结算系统按照计费规则计算各项费用并进行输出,这个过程称为计费。 目前系统主要支持的费用项有货款、物流费、平台佣金、仓储费、推广费、售后费、VAT税、清关费等,本文以货款、物流费、平台佣金为例阐述计费优化的思路和具体实践。 为什么要优化?总结来说,业务上计费科目越来越多,难以快速支持;技术上代码臃肿,可读性差,稳定性不高,难以维护。 计费作为结算系统的基础服务,在系统建立初期就已存在,跟大多数系统一样,早期业务简单,没有必要过度设计,随着系统规模见长,各种需求、逻辑掺杂进来,代码基本都写在一个大类中,很难完全理解业务。并且有些不在计费范围内的业务代码,例如清分和通知上下游,也耦合在计费模块中,业务边界混杂。 计费功能核心流程现状计费流程图计费功能核心代码现状/** *订单计费服务 */ publicclassOrderBillingService{ privateLockerlocker; /** *计费 * *@paramorder订单 *@paramevent订单事件 */ publicvoidbilling(OrderDTOorder,OrderEventevent){ //1.预校验 if(!"ORDER_SIGN".equals(event.getEventType())){ return; } //2.并发检查 if(!locker.tryLock(order.getOrderNumber())){ return; } //3.幂等检查 BillingOrderbillingOrder=getByOrderNumber(order.getOrderNumber()); if(billingOrder!=null){ return; } //4.模型转换 BillingDTObillingDTO=translate(order); MerchantDTOseller=getSeller(order.getSellerId()); //5.加载计费规则 Contractcontract=loadBillingContract(billingDTO,seller); Promotionpromotion=loadBillingPromotion(billingDTO,seller); //6.开始结算计费 BigDecimalorderAmount=billingDTO.getOrderAmount();//订单金额 BigDecimalbillingAmount=BigDecimal.ZERO; BigDecimallogisticsFeeTotal=billingDTO.getLogisticsFee();//订单物流费 ListBillingSkuDTOorderSkuList=billingDTO.getSkuList();//计费明细 for(BillingSkuDTObillingSkuDTO:orderSkuList){ BigDecimalskuBillingAmount=billingSkuDTO.getAmount();//明细计费金额 //6.1.计算物流费 BigDecimallogisticsFee=billingSkuDTO.getAmount() .divide(orderAmount,6,BigDecimal.ROUND_HALF_UP) .multiply(logisticsFeeTotal);//示例按金额占比分摊物流费,实际分摊比这要复杂 FeeDTOlogisticsFeeDTO=newFeeDTO(); logisticsFeeDTO.setFeeType("logistics"); logisticsFeeDTO.setFee(logisticsFee); logisticsFeeDTO.setAmount(logisticsFee); billingSkuDTO.addFee(logisticsFeeDTO); skuBillingAmount=skuBillingAmount.subtract(logisticsFee); //6.2.计算佣金 BigDecimalcommissionFeeRate=contract.getCommissionFeeRate(); BigDecimalcommissionFee=billingSkuDTO.getAmount().multiply(commissionFeeRate); FeeDTOcommissionFeeDTO=newFeeDTO(); commissionFeeDTO.setFeeType("commission"); commissionFeeDTO.setFee(commissionFee); commissionFeeDTO.setAmount(commissionFee); billingSkuDTO.addFee(commissionFeeDTO); skuBillingAmount=skuBillingAmount.subtract(commissionFee); //6.3.计算货款 billingSkuDTO.setBillingAmount(skuBillingAmount); } //7.开始优惠计费 for(BillingSkuDTObillingSkuDTO:orderSkuList){ BigDecimalskuBillingAmount=billingSkuDTO.getBillingAmount();//明细计费金额 ListFeeDTOfeeDTOList=billingSkuDTO.getFeeList(); for(FeeDTOfeeDTO:feeDTOList){ //该费用可优惠 if(promotion.isPromotion(feeDTO,billingDTO)){ //获取优惠金额 BigDecimalpromotionFee=promotion.getPromotionFee(feeDTO,billingDTO); feeDTO.setPromotion(promotionFee); feeDTO.setAmount(feeDTO.getAmount().subtract(promotionFee)); skuBillingAmount=skuBillingAmount.add(promotionFee); } } //重新计算货款 billingSkuDTO.setBillingAmount(skuBillingAmount); billingAmount=billingAmount.add(skuBillingAmount); } billingDTO.setBillingAmount(billingAmount); //8.持久化 billingOrder=save(billingDTO); //9.清分 clearing(billingOrder); //10.计费完成 publish(billingOrder); } 以上代码做了很大的简化和提炼,但是仍不难发现其中存在的问题。入口的 billing 方法过于复杂,既有校验代码,又有核心计费逻辑,还有计费后的持久化,以及计费职责范围以外的清分、回调等。虽然多数逻辑做了抽离,但是整体逻辑仍然太重,职责很多,相当臃肿,导致计费核心很难扩展。 此次重构的目标就是解决以上问题,让核心逻辑高度内聚,可插拔易扩展,流程可编排、节点可复用,同时逻辑跟其他模块松解耦、不粘连。 重构思路和目标计费流程节点清晰,各个节点业务逻辑比较容易划分边界,所以重构思路上以大类拆分、节点复用为主,比如预校验、模型转换、持久化和清分这几个步骤比较通用,其他各业务计费步骤在逻辑上比较内聚,这两种情况都可以抽象出节点,通过责任链进行编排、重构。 针对上述提到面临的问题,提出以下目标。 易扩展:可扩展性强,流程节点可插拔、可调整,不用大幅改动即可快速支持新需求。 好运维:代码结构清晰,容易理解,出现问题好定位。 使用责任链重构责任链模式是一种行为设计模式, 允许你将请求沿着处理者链进行发送。收到请求后, 每个处理者均可对请求进行处理, 或将其传递给链上的下个处理者。 责任链计费类图计费类图定义处理者接口,拆分实现具体的处理者。其中费用计算作为计费整体流程中的一环,自身逻辑内聚,职责单一且又有固定的流程,单独拆分出一个子链出来。 重构后的代码//流程配置 publicclassBillingHandlerChainConfig{ publicBillingHandlerChaingetOrderBillingHandlerChain(){ BillingHandlerChainorderChain=newOrderBillingHandlerChain(); ListBillingHandlerhandlers=newArrayList(); //1.校验 handlers.add(newPreCheckBillingHandler()); //2.模型转换 handlers.add(newTranslateBillingHandler()); //3.计费规则 handlers.add(newRuleBillingHandler()); //4.计费 CalculateBillingHandlercalculateBillingHandler=newCalculateBillingHandler(); handlers.add(calculateBillingHandler); ListBillingHandlercalculateHandlers=newArrayList(); calculateBillingHandler.setHandlers(calculateHandlers); //4.1.物流费计算 calculateHandlers.add(newLogisticsBillingHandler()); //4.2.佣金计算 calculateHandlers.add(newCommissionBillingHandler()); //4.3.优惠计算 calculateHandlers.add(newPromotionBillingHandler()); //4.4.货款计算 calculateHandlers.add(newGoodsBillingHandler()); //5.持久化 handlers.add(newSaveBillingHandler()); //6.发布事件 handlers.add(newPublishBillingHandler()); orderChain.setHandlers(handlers); returnorderChain; } } //计费服务入口 publicclassOrderBillingService{ privateBillingHandlerChainorderBillingHandlerChain; privatevoidbilling(OrderDTOorder,OrderEventevent){ BillingContextcontext=initContext(order,event); orderBillingHandlerChain.handle(context); } } //订单计费主链 publicclassOrderBillingHandlerChainimplementsBillingHandlerChain{ privateListBillingHandlerhandlers; @Override publicvoidsetHandlers(ListBillingHandlerhandlers){ this.handlers=handlers; } @Override publicbooleanhandle(BillingContextcontext){ if(handlers==null){ thrownewIllegalStateException("订单计费没有可用流程"); } for(BillingHandlerhandler:handlers){ if(!handler.handle(context)){ returnfalse; } } returntrue; } } //计费处理器/计费子链 publicclassCalculateBillingHandlerimplementsBillingHandler,BillingHandlerChain{ privateListBillingHandlerhandlers; @Override publicvoidsetHandlers(ListBillingHandlerhandlers){ this.handlers=handlers; } @Override publicbooleanhandle(BillingContextcontext){ if(handlers==null){ thrownewIllegalStateException("计费子链没有可用流程"); } for(BillingHandlerhandler:handlers){ if(!handler.handle(context)){ returnfalse; } } returntrue; } } //物流费处理器 publicclassLogisticsBillingHandlerimplementsBillingHandler{ @Override publicbooleanhandle(BillingContextcontext){ BillingDTObillingDTO=context.getBillingOrder(); BigDecimalorderAmount=billingDTO.getOrderAmount();//订单金额 BigDecimallogisticsFeeTotal=billingDTO.getLogisticsFee();//订单物流费 ListBillingSkuDTOorderSkuList=billingDTO.getSkuList();//计费明细 for(BillingSkuDTObillingSkuDTO:orderSkuList){ BigDecimalskuBillingAmount=billingSkuDTO.getBillingAmount();//明细计费金额 BigDecimallogisticsFee=billingSkuDTO.getAmount() .divide(orderAmount,6,BigDecimal.ROUND_HALF_UP) .multiply(logisticsFeeTotal);//示例按金额占比分摊物流费,实际分摊比这要复杂 FeeDTOlogisticsFeeDTO=newFeeDTO(); logisticsFeeDTO.setFeeType("logistics"); logisticsFeeDTO.setFee(logisticsFee); logisticsFeeDTO.setAmount(logisticsFee); billingSkuDTO.addFee(logisticsFeeDTO); skuBillingAmount=skuBillingAmount.subtract(logisticsFee); billingSkuDTO.setBillingAmount(skuBillingAmount); } returntrue; } } //优惠处理器 publicclassPromotionBillingHandlerimplementsBillingHandler{ @Override publicbooleanhandle(BillingContextcontext){ BillingDTObillingDTO=context.getBillingOrder(); ListBillingSkuDTOorderSkuList=billingDTO.getSkuList();//计费明细 Promotionpromotion=context.getPromotion(); //开始优惠计费 for(BillingSkuDTObillingSkuDTO:orderSkuList){ BigDecimalskuBillingAmount=billingSkuDTO.getBillingAmount();//明细计费金额 ListFeeDTOfeeDTOList=billingSkuDTO.getFeeList(); for(FeeDTOfeeDTO:feeDTOList){ //该费用可优惠 if(promotion.isPromotion(feeDTO,billingDTO)){ //获取优惠金额 BigDecimalpromotionFee=promotion.getPromotionFee(feeDTO,billingDTO); feeDTO.setPromotion(promotionFee); feeDTO.setAmount(feeDTO.getAmount().subtract(promotionFee)); skuBillingAmount=skuBillingAmount.add(promotionFee); } } billingSkuDTO.setBillingAmount(skuBillingAmount); } returntrue; } } 原来逻辑中的清分、计费完成通知上游业务两个环节,本质上不在计费业务的范围内,只是通过计费完成来触发的其他业务,在此次改造中完全独立出去,改由计费的最后一环「发布计费完成事件」来驱动,保持计费业务高内聚。 一些思考腐化产生的原因代码腐化是不可避免的,只能尽量减轻。 腐化产生的原因很多,可能是缺乏良好的设计,一开始就没做好规划,后面业务代码堆砌,就更加混乱,难以维护了。本文所针对的计费模块,就是这个问题。 也可能是缺乏良好的实践,虽然有好的设计和编码标准,但是规约没有执行到位,也是出现腐化的一个重要原因。 当然,这两种原因也都有一些客观因素存在,比如初期业务简单,没必要大搞设计,或者为了需求快速上线,做了一些妥协,成了技术债务。再比如人员更替,技术水平和认知各不相同,后来者也可能不会遵照之前的约定。 如何减轻腐化腐化带来开发效率的降低和系统风险的提升,在实践中可以从下面几点来减轻腐化带来的影响。 制定规约建立包括编码标准,代码审查和单元测试相关的规约,定期总结执行情况,养成防腐的习惯。 定期重构针对已经腐化的代码,定期重构,清理无效代码,去除冗余,改善代码结构,增强可读性,提高可扩展性,降低维护成本。 阅读原文

上一篇:2018-10-07_学界 | 全局最优解?为什么SGD能令神经网络的损失降到零 下一篇:2025-07-10_一个IP,如何多维解题亲子营销?

TAG标签:

18
网站开发网络凭借多年的网站建设经验,坚持以“帮助中小企业实现网络营销化”为宗旨,累计为4000多家客户提供品质建站服务,得到了客户的一致好评。如果您有网站建设网站改版域名注册主机空间手机网站建设网站备案等方面的需求...
请立即点击咨询我们或拨打咨询热线:13245491521 13245491521 ,我们会详细为你一一解答你心中的疑难。
项目经理在线

相关阅读 更多>>

猜您喜欢更多>>

我们已经准备好了,你呢?
2022我们与您携手共赢,为您的企业营销保驾护航!

不达标就退款

高性价比建站

免费网站代备案

1对1原创设计服务

7×24小时售后支持

 

全国免费咨询:

13245491521

业务咨询:13245491521 / 13245491521

节假值班:13245491521()

联系地址:

Copyright © 2019-2025      ICP备案:沪ICP备19027192号-6 法律顾问:律师XXX支持

在线
客服

技术在线服务时间:9:00-20:00

在网站开发,您对接的直接是技术员,而非客服传话!

电话
咨询

13245491521
7*24小时客服热线

13245491521
项目经理手机

微信
咨询

加微信获取报价