Tomcat 架构原理解析到架构设计借鉴 (11)

上市企业:判断名称是否存在 ,不存在则发送邮件并中止计算-> 从数据库拉取财报数据,初始化查验日志、生成一条报告记录,触发计算-> 根据失败与成功修改任务状态 。

重要的 ”变“ 与 ”不变“,

不变的是整个流程是初始化查验日志、初始化一条报告前期校验数据(若是上市公司校验不通过还需要构建邮件数据并发送)、从不同来源拉取财报数据并且适配通用数据、然后触发计算,任务异常与成功都需要修改状态。

变化的是上市与非上市校验规则不一样,获取财报数据方式不一样,两种方式的财报数据需要适配

整个算法流程是固定的模板,但是需要将算法内部变化的部分具体实现延迟到不同子类实现,这正是模板方法模式的最佳场景。

public abstract class AbstractAnalysisTemplate { /** * 提交财报分析模板方法,定义骨架流程 * @param reportAnalysisRequest * @return */ public final FinancialAnalysisResultDTO doProcess(FinancialReportAnalysisRequest reportAnalysisRequest) { FinancialAnalysisResultDTO analysisDTO = new FinancialAnalysisResultDTO(); // 抽象方法:提交查验的合法校验 boolean prepareValidate = prepareValidate(reportAnalysisRequest, analysisDTO); log.info("prepareValidate 校验结果 = {} ", prepareValidate); if (!prepareValidate) { // 抽象方法:构建通知邮件所需要的数据 buildEmailData(analysisDTO); log.info("构建邮件信息,data = {}", JSON.toJSONString(analysisDTO)); return analysisDTO; } String reportNo = FINANCIAL_REPORT_NO_PREFIX + reportAnalysisRequest.getUserId() + SerialNumGenerator.getFixLenthSerialNumber(); // 生成分析日志 initFinancialAnalysisLog(reportAnalysisRequest, reportNo); // 生成分析记录 initAnalysisReport(reportAnalysisRequest, reportNo); try { // 抽象方法:拉取财报数据,不同子类实现 FinancialDataDTO financialData = pullFinancialData(reportAnalysisRequest); log.info("拉取财报数据完成, 准备执行计算"); // 测算指标 financialCalcContext.calc(reportAnalysisRequest, financialData, reportNo); // 设置分析日志为成功 successCalc(reportNo); } catch (Exception e) { log.error("财报计算子任务出现异常", e); // 设置分析日志失败 failCalc(reportNo); throw e; } return analysisDTO; } }

最后新建两个子类继承该模板,并实现抽象方法。这样就将上市与非上市两种类型的处理逻辑解耦,同时又复用了代码。

策略模式

需求是这样,要做一个万能识别银行流水的 excel 接口,假设标准流水包含【交易时间、收入、支出、交易余额、付款人账号、付款人名字、收款人名称、收款人账号】等字段。现在我们解析出来每个必要字段所在 excel 表头的下标。但是流水有多种情况:

一种就是包含所有标准字段。

收入、支出下标是同一列,通过正负来区分收入与支出。

收入与支出是同一列,有一个交易类型的字段来区分。

特殊银行的特殊处理。

也就是我们要根据解析对应的下标找到对应的处理逻辑算法,我们可能在一个方法里面写超多 if else 的代码,整个流水处理都偶合在一起,假如未来再来一种新的流水类型,还要继续改老代码。最后可能出现 “又臭又长,难以维护” 的代码复杂度。

这个时候我们可以用到策略模式将不同模板的流水使用不同的处理器处理,根据模板找到对应的策略算法去处理。即使未来再加一种类型,我们只要新加一种处理器即可,高内聚低耦合,且可拓展。

定义处理器接口,不同处理器去实现处理逻辑。将所有的处理器注入到 BankFlowDataHandler 的data_processor_map中,根据不同的场景取出对已经的处理器处理流水。

public interface DataProcessor { /** * 处理流水数据 * @param bankFlowTemplateDO 流水下标数据 * @param row * @return */ BankTransactionFlowDO doProcess(BankFlowTemplateDO bankFlowTemplateDO, List<String> row); /** * 是否支持处理该模板,不同类型的流水策略根据模板数据判断是否支持解析 * @return */ boolean isSupport(BankFlowTemplateDO bankFlowTemplateDO); } // 处理器的上下文 @Service @Slf4j public class BankFlowDataContext { // 将所有处理器注入到 map 中 @Autowired private List<DataProcessor> processors; // 找对对应的处理器处理流水 public void process() { DataProcessor processor = getProcessor(bankFlowTemplateDO); for(DataProcessor processor : processors) { if (processor.isSupport(bankFlowTemplateDO)) { // row 就是一行流水数据 processor.doProcess(bankFlowTemplateDO, row); break; } } } }

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wpjzfz.html