设计模式复盘
一、背景
在项目中,对于单据的扩展是基于类似于接口扩展实现的。从业务横行来看,业务有A、B、C;从纵向来看,单个业务逻辑编排也可以划分为基础数据查询,决策判断,逻辑执行三大块。
单据扩展:平台构建单据基本信息,不同业务往单据中构建不同的信息。
二、抽象
将业务玩法+业务逻辑抽象可得策略模式和模版方法模式思维,可将二者通过Spring的加载机制链接在一起共同实现代码的高内聚,低耦合的特性。
三、线上运行版本
业务上下文
public class BusinessContext {private String type;private Map<String , String> features;}
1、抽象业务逻辑编排并且定位为接口,为策略模式提供基础
public interface BusinessStrategy {/*** desc: 查询节点:查询决策节点所需的数据*/Object query(BusinessContext businessContext);/*** desc: 决策节点:通过传入的业务上下文进行判断*/boolean isHandle(Object query);/*** desc: 业务逻辑具体执行节点*/void handle(BusinessContext businessContext ,Object query , Map<String, String> orderFeature);/*** desc: 策略管理类调用节点1*/default void execute(BusinessContext businessContext , Map<String, String> orderFeature) {Object query = query(businessContext);boolean handleFlag = isHandle(businessContext);if (handleFlag) {handle(businessContext, query , orderFeature);}}}
2、策略模式管理类和扩展入口
public class BusinessStrategyManager {@Resourceprivate List<BusinessStrategy> strategyList;public Map<String, String> doExecute(BusinessContext businessContext){Map<String, String> res = new HashMap<>();for (BusinessStrategy businessStrategy : strategyList) {//循环调用不同的实现businessStrategy.execute(businessContext , res);if (MapUtils.isNotEmpty(res)) {break;}}return res;}}
3、A业务实现(如果有其他实现,followA实现即可,不需要关心具体的bundle调用)
public class BusinessStrategyAImpl implements BusinessStrategy {@Overridepublic Object query(BusinessContext businessContext) {return "查询用来判断的数据";}/*** desc: 决策节点:通过传入的业务上下文进行判断** @param query*/@Overridepublic boolean isHandle(Object query) {System.out.println("判断的数据进行判断");return true;}/*** desc: 业务逻辑具体执行节点** @param businessContext* @param query* @param orderFeature*/@Overridepublic void handle(BusinessContext businessContext, Object query, Map<String, String> orderFeature) {System.out.println("业务逻辑执行");orderFeature.put("A" , "BusinessStrategyAImpl");}
}
四、运行版本中的问题
在策略模式管理类和扩展入口,最初的运行版本对于businessStrategy.execute()方法的异常是自己捕获的,并没有往外抛出,导致了单据未补充正确的信息,但是单据正常的创建了,以至于后续链路全部异常。
从业务视角下看,单据扩展信息补充发生异常时,应当阻断单据创建。从扩展框架的视角上看,实现类的异常应当直接抛出,不能被框架消化,否侧会导致使用者无法定位问题和发生预期之外的异常
五、复盘优化版本
该框架在线上运行过程中,虽然无异常问题,但是从代码层面来看,依然具有优化的空间。
通用的策略框架适用于调用方法清楚的知道需要调用那个策略类,调用方直接指定策略类,但是在当前扩展中,调用方也不知道具体调用策略类,需要业务实现类中查询数据之后再进行判断,对指定策略类的步骤进行了后置,导致通用策略类框架不适用于当前情况。
问题详情
如果有n个实现类,最差的情况需要把前面的n-1个实现类执行完成之后,才会执行到第n个实现类。
-
- 前n-1个实现类中的基础数据查询阶段还不能出现异常(例如超时异常),否则都执行不到第n个实现类;
- 前n-1个实现类中,基础数据查询到rpc调用耗时较久,性能较低
优化思路
- 将基础数据查询中的通用部分,例如orderA信息,orderB在策略模式管理类和扩展入口中先查询再透传到链路中,故不需要每一个实现类查询一次
- 再通过实现类+所需单据信息分为不同的组,可最大限度的减少rpc调用(可配置实现)
六、优化框架
业务上下文
public class BusinessContext {private String type;private Map<String , String> features;}
1、抽象业务逻辑编排并且定位为接口,为策略模式提供基础
public interface BusinessStrategy2 {/*** desc: 决策节点*/boolean isHandle(BusinessContext businessContext);/*** desc: 业务逻辑具体执行节点*/void handle(BusinessContext businessContext, Map<String, String> orderFeature);/*** desc: 策略管理类调用节点2*/default void execute2(BusinessContext businessContext , Object query, Map<String, String> orderFeature) {boolean handleFlag = isHandle(businessContext);if (handleFlag) {handle(businessContext, orderFeature);}}}
2、策略模式管理类和扩展入口
public class BusinessStrategyManager2 {@Resourceprivate List<BusinessStrategy2> strategyList;private Map<String, List<BusinessStrategy2>> strategyMap = new HashMap<>();//配置项:配置业务实例和所需查询结果private Map<String, String> strategyGroupMap = new HashMap() {{put("A", "orderA");put("A1", "orderA");put("A2", "orderA");put("B", "orderB");put("B1", "orderB");put("B2", "orderB");}};//配置项:配置所需查询结果和查询对应的实例全类名private Map<String, String> queryGroupMap = new HashMap() {{put("orderA", "com.example.testproject.design.strategy.update.impl.QueryOrderAImpl");put("orderB", "com.example.testproject.design.strategy.update.impl.QueryOrderBImpl");}};@PostConstructpublic void buildStrategyMap() {//对业务实例根据所需查询结果进行分组for (BusinessStrategy2 strategy : strategyList) {if (strategyGroupMap.containsKey(strategy.getClass().getName())) {List<BusinessStrategy2> list = strategyMap.get(strategyGroupMap.get(strategy.getClass().getName()));if (Objects.isNull(list)) {list = new ArrayList<>();}list.add(strategy);strategyMap.put(strategyGroupMap.get(strategy.getClass().getName()), list);}}}public Map<String, String> doExecute(BusinessContext businessContext) {Map<String, String> res = new HashMap<>();for (Map.Entry<String, List<BusinessStrategy2>> stringListEntry : strategyMap.entrySet()) {//不同所需查询结果的组,获取不同的查询实例进行查询if (queryGroupMap.containsKey(stringListEntry.getKey())) {//获取配置的查询实例全类名String className = queryGroupMap.get(stringListEntry.getKey());//获取实例QueryOrderInter queryOrderInter = SpringUtils.getBean(className, QueryOrderInter.class);if (Objects.isNull(queryOrderInter)){throw new RuntimeException("未找到对应的查询实例,className={}" + className);}Object query = queryOrderInter.query(businessContext);List<BusinessStrategy2> value = stringListEntry.getValue();//所需查询结果的相同的组对查询结果进行消费for (BusinessStrategy2 strategy : value) {strategy.execute2(businessContext, query, res);if (MapUtils.isNotEmpty(res)) {break;}}}}return res;}}
3、查询抽象接口
public interface QueryOrderInter {Object query(BusinessContext businessContext);}
4、查询orderA
public class QueryOrderAImpl implements QueryOrderInter {@Overridepublic Object query(BusinessContext businessContext) {System.out.println("查询orderA");return "orderA";}
}
相关文章:
设计模式复盘
一、背景 在项目中,对于单据的扩展是基于类似于接口扩展实现的。从业务横行来看,业务有A、B、C;从纵向来看,单个业务逻辑编排也可以划分为基础数据查询,决策判断,逻辑执行三大块。 单据扩展:平…...

电力能源三维可视化合集 | 图扑数字孪生
电力能源是现代社会发展和运行的基石,渗透于工业、商业、农业、家庭生活等方方面面,它为经济、生活质量、环境保护和社会发展提供了巨大的机会和潜力。图扑软件应用自研 HT for Web 强大的渲染引擎,助力现代化的电力能源数字孪生场景…...

What is `@Repository` does?
Repository 是Spring注解,标识数据访问层组件(DAO, Data Access Object) 当一个类被标记为 Repository 时: 1、组件扫描与自动代理: Spring通过组件扫描(Component Scan)机制发现带有 Reposit…...

c# 自定义 滑块TrackBar
辛苦半天做出来的,如果觉得好用,记得点赞 效果图如下: 具体操作: 1 、添加代码(代码在下面),重新生成下整个工程,在工具栏中就出现控件,将控件拖到窗体中 2、只需要调整…...
MyBatis整合分页插件PageHelper的使用和说明
MyBatis,作为目前流行的ORM框架,大大方便了日常开发。而对于分页查询,虽然可以通过SQL的limit语句实现,但是比较繁琐。而MyBatis PageHelper的出现,则解决了这一痛点。这里将介绍如何在Spring Boot、MyBatis的环境中通…...

情人节专属--HTML制作情人节告白爱心
💕效果展示 💕html展示 <!DOCTYPE html> <html lang="en" > <head>...

带你学C语言-指针(4)
目录 编辑 ⚾0.前言 🏀1.回调函数 ⚽2.qsort 🏉2.1 qsort函数的模拟实现 🎾3.sizeof与strlen对比 🎾4.结束语 ⚾0.前言 言C之言,聊C之识,以C会友,共向远方。各位CSDN的各位你们好啊&…...
ACL访问控制列表
ACL:访问控制列表 在路由器流量进或出接口上,匹配流量产生动作-- 允许 拒绝 (访问限制)定义感兴趣流量--- 匹配流量后,将流量提交给其他的协议进行策略 匹配规则: 至上而下逐一匹配,上条匹配按…...

sqli-labs关卡25(基于get提交的过滤and和or的联合注入)
文章目录 前言一、回顾上一关知识点二、靶场第二十五关通关思路1、判断注入点2、爆字段个数3、爆显位位置4、爆数据库名5、爆数据库表名6、爆数据库列名7、爆数据库数据 总结 前言 此文章只用于学习和反思巩固sql注入知识,禁止用于做非法攻击。注意靶场是可以练习的…...

机器学习周刊第六期:哈佛大学机器学习课、Chatbot Ul 2.0 、LangChain v0.1.0、Mixtral 8x7B
— date: 2024/01/08 — 吴恩达和Langchain合作开发了JavaScript 生成式 AI 短期课程:《使用 LangChain.js 构建 LLM 应用程序》 大家好,欢迎收看第六期机器学习周刊 本期介绍10个内容,涉及Python、机器学习、大模型等,目录如下ÿ…...

【算法与数据结构】Java实现查找与排序
文章目录 第一部分:查找算法二分查找插值查找分块查找哈希查找树表查找 第二部分:排序算法冒泡排序选择排序插入排序快速排序 总结 第一部分:查找算法 二分查找 也叫做折半查找,属于有序查找算法。 前提条件:数组数据…...

边缘计算的挑战和机遇(结合RDH-EI)
边缘计算的挑战和机遇 边缘计算面临着数据安全与隐私保护、网络稳定性等挑战,但同时也带来了更强的实时性和本地处理能力,为企业降低了成本和压力,提高了数据处理效率。因此,边缘计算既带来了挑战也带来了机遇,需要我…...

详解IP安全:IPSec协议簇 | AH协议 | ESP协议 | IKE协议_ipsec esp
目录 IP安全概述 IPSec协议簇 IPSec的实现方式 AH(Authentication Header,认证头) ESP(Encapsulating Security Payload,封装安全载荷) IKE(Internet Key Exchange,因特网密钥…...
【图论】树的直径
树的直径即为一棵树中距离最远的两点之间的路径 方法一:DFS 先以任意一点为起点跑一遍dfs,记录离起点距离最远的点p(这个点一定是直径的一个端点,感性理解一下不证明了),然后再以最远点再跑一遍dfs&#…...

制作一个Python聊天机器人
我们学习一下如何使用 ChatterBot 库在 Python 中创建聊天机器人,该库实现了各种机器学习算法来生成响应对话,还是挺不错的 什么是聊天机器人 聊天机器人也称为聊天机器人、机器人、人工代理等,基本上是由人工智能驱动的软件程序࿰…...

docker 使用 vcs/2018 Verdi等 eda 软件
好不容易在ubuntu 安装好了eda软件,转眼就发现了自己的无知。 有博主几年前就搞定了docker上的EDA工具。而且更全,更简单。只恨自己太无知啊。 Synopsys EDA Tools docker image - EDA资源使用讨论 - EETOP 创芯网论坛 (原名:电子顶级开发网…...

Git教程学习:01 Git简介与安装
目录 1 版本控制1.1 什么是版本控制系统?1.2 本地版本控制系统1.3 集中式版本控制系统1.4 分布式版本控制系统 2 Git简史3 Git的安装3.1 在Linux上安装3.2 初次运行Git前的配置 1 版本控制 1.1 什么是版本控制系统? 版本控制系统(Version Control Syst…...

写操作系统之开发加载器
这篇文章写的很好是理解操作系统加载部分的基础 https://www.cnblogs.com/chuganghong/p/15415208.html loader的功能是: 从软盘中把操作系统内核读取到内存中。 进入保护模式。 把内存中的操作系统内核重新放置到内存中。 执行操作系统内核。 如果理解不了上面的…...

openlayers [九] 地图覆盖物overlay三种常用用法 popup弹窗,marker标注,text文本
文章目录 简介overlay 实现popup弹窗overlay 实现label 标注信息overlay实现 text 文本信息完整代码 简介 常见的地图覆盖物为这三种类型,如:popup弹窗、label标注信息、text文本信息等。 overlay 实现popup弹窗 方法详解 实例一个 new Overlay()&…...

rabbitmq-java基础详解
一、rabbitmq是什么? 1、MQ定义 MQ(Message Queue)消息队列 主要解决:异步处理、应用解耦、流量削峰等问题,是分布式系统的重要组件,从而实现高性能,高可用,可伸缩和最终一致性的架…...
Ubuntu系统下交叉编译openssl
一、参考资料 OpenSSL&&libcurl库的交叉编译 - hesetone - 博客园 二、准备工作 1. 编译环境 宿主机:Ubuntu 20.04.6 LTSHost:ARM32位交叉编译器:arm-linux-gnueabihf-gcc-11.1.0 2. 设置交叉编译工具链 在交叉编译之前&#x…...

2025年能源电力系统与流体力学国际会议 (EPSFD 2025)
2025年能源电力系统与流体力学国际会议(EPSFD 2025)将于本年度在美丽的杭州盛大召开。作为全球能源、电力系统以及流体力学领域的顶级盛会,EPSFD 2025旨在为来自世界各地的科学家、工程师和研究人员提供一个展示最新研究成果、分享实践经验及…...

解决Ubuntu22.04 VMware失败的问题 ubuntu入门之二十八
现象1 打开VMware失败 Ubuntu升级之后打开VMware上报需要安装vmmon和vmnet,点击确认后如下提示 最终上报fail 解决方法 内核升级导致,需要在新内核下重新下载编译安装 查看版本 $ vmware -v VMware Workstation 17.5.1 build-23298084$ lsb_release…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...

处理vxe-table 表尾数据是单独一个接口,表格tableData数据更新后,需要点击两下,表尾才是正确的
修改bug思路: 分别把 tabledata 和 表尾相关数据 console.log() 发现 更新数据先后顺序不对 settimeout延迟查询表格接口 ——测试可行 升级↑:async await 等接口返回后再开始下一个接口查询 ________________________________________________________…...
Go 并发编程基础:通道(Channel)的使用
在 Go 中,Channel 是 Goroutine 之间通信的核心机制。它提供了一个线程安全的通信方式,用于在多个 Goroutine 之间传递数据,从而实现高效的并发编程。 本章将介绍 Channel 的基本概念、用法、缓冲、关闭机制以及 select 的使用。 一、Channel…...

逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
探索Selenium:自动化测试的神奇钥匙
目录 一、Selenium 是什么1.1 定义与概念1.2 发展历程1.3 功能概述 二、Selenium 工作原理剖析2.1 架构组成2.2 工作流程2.3 通信机制 三、Selenium 的优势3.1 跨浏览器与平台支持3.2 丰富的语言支持3.3 强大的社区支持 四、Selenium 的应用场景4.1 Web 应用自动化测试4.2 数据…...

若依登录用户名和密码加密
/*** 获取公钥:前端用来密码加密* return*/GetMapping("/getPublicKey")public RSAUtil.RSAKeyPair getPublicKey() {return RSAUtil.rsaKeyPair();}新建RSAUti.Java package com.ruoyi.common.utils;import org.apache.commons.codec.binary.Base64; im…...

2.3 物理层设备
在这个视频中,我们要学习工作在物理层的两种网络设备,分别是中继器和集线器。首先来看中继器。在计算机网络中两个节点之间,需要通过物理传输媒体或者说物理传输介质进行连接。像同轴电缆、双绞线就是典型的传输介质,假设A节点要给…...