设计模式复盘
一、背景
在项目中,对于单据的扩展是基于类似于接口扩展实现的。从业务横行来看,业务有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)消息队列 主要解决:异步处理、应用解耦、流量削峰等问题,是分布式系统的重要组件,从而实现高性能,高可用,可伸缩和最终一致性的架…...
RestClient
什么是RestClient RestClient 是 Elasticsearch 官方提供的 Java 低级 REST 客户端,它允许HTTP与Elasticsearch 集群通信,而无需处理 JSON 序列化/反序列化等底层细节。它是 Elasticsearch Java API 客户端的基础。 RestClient 主要特点 轻量级ÿ…...
【Axure高保真原型】引导弹窗
今天和大家中分享引导弹窗的原型模板,载入页面后,会显示引导弹窗,适用于引导用户使用页面,点击完成后,会显示下一个引导弹窗,直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…...
【JavaEE】-- HTTP
1. HTTP是什么? HTTP(全称为"超文本传输协议")是一种应用非常广泛的应用层协议,HTTP是基于TCP协议的一种应用层协议。 应用层协议:是计算机网络协议栈中最高层的协议,它定义了运行在不同主机上…...
Cesium1.95中高性能加载1500个点
一、基本方式: 图标使用.png比.svg性能要好 <template><div id"cesiumContainer"></div><div class"toolbar"><button id"resetButton">重新生成点</button><span id"countDisplay&qu…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
页面渲染流程与性能优化
页面渲染流程与性能优化详解(完整版) 一、现代浏览器渲染流程(详细说明) 1. 构建DOM树 浏览器接收到HTML文档后,会逐步解析并构建DOM(Document Object Model)树。具体过程如下: (…...
Mac软件卸载指南,简单易懂!
刚和Adobe分手,它却总在Library里给你写"回忆录"?卸载的Final Cut Pro像电子幽灵般阴魂不散?总是会有残留文件,别慌!这份Mac软件卸载指南,将用最硬核的方式教你"数字分手术"࿰…...
C++中string流知识详解和示例
一、概览与类体系 C 提供三种基于内存字符串的流,定义在 <sstream> 中: std::istringstream:输入流,从已有字符串中读取并解析。std::ostringstream:输出流,向内部缓冲区写入内容,最终取…...
零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...
select、poll、epoll 与 Reactor 模式
在高并发网络编程领域,高效处理大量连接和 I/O 事件是系统性能的关键。select、poll、epoll 作为 I/O 多路复用技术的代表,以及基于它们实现的 Reactor 模式,为开发者提供了强大的工具。本文将深入探讨这些技术的底层原理、优缺点。 一、I…...
