设计模式在业务系统中的应用
Hollis
共 12913字,需浏览 26分钟
· 2021-07-31
本文的重点在于说明工作中所使用的设计模式,为了能够更好的理解设计模式,首先简单介绍一下业务场景。使用设计模式,可以简化代码、提高扩展性、可维护性和复用性。有哪些设计模式,这里就不再介绍了,网上很多,本文只介绍所用到设计模式。
一 线路检查工具
1 意义
为什么需要线路检查工具呢,有以下几个方面的原因:
每逢大促都需要进行各网络和各行业的线路调整,调整完成之后,是否得到期望状态,需要检查确认。
上下游应用之间数据的一致性检查,如果存在不一致,可能会在订单履行时造成卡单。
有些问题发生后,业务同学需要全面检查一遍线路数据,判断是否符合预期。
各领域之间的数据变更缺乏联动性,导致资源和线路出现不一致。
以前每次大促,都是技术同学现场编写代码捞数据给到业务同学,而且因为人员流动性较大,代码可复用性较低,导致重复劳动。产品化后,可以方便地传承下去,避免不必要的重复劳动。
每次因为时间紧急,现场写的代码都比较简单,经常是直接将数据打印到标准输出,然后复制出来,人工拆分转成Excel格式;这样的过程要进行多次,占用太多技术同学的时间。产品化后,解放了技术同学,业务同学可以自己在页面操作。
很多数据检查,是每次大促都会进行的,业务同学与技术同学之间来回沟通的成本较高。产品化后,可以避免这些耗时耗力的沟通,大家可以把更多的时间放在其他的大促保障工作上。
时效对齐检查:确保履行分单正常。
弱控线路与表达网络一致性:确保履行和路由不会因为线路缺失而卡单。
资源映射和编码映射一致:前者是表达线路时所用,后者是订单履约时所用,确保表达和履约能够一致。
检查线路数量:统计现存线路的情况。
commonParamCheck方法:进行参数合法性检查,不合法的情况下,直接返回。
createFileName方法:创建文件名称。
createTaskRecord方法:创建检查任务。
runDataCheck方法:进行数据检查,这是一个抽象方法,所有检查工具都要实现此方法,以实现自己的逻辑。
uploadToOSS方法:将检查结果上传到OSS,便于下载。
updateRouteTask方法:结束时更新任务为完成。
/**
* 数据检查工具产品化对外服务接口
* @author xxx
* @since xxx
* */
public interface DataCheckProductService {
/**
* 数据检查
* @param requestDTO 请求参数
* */
<T> BaseResult<Long> dataCheck(DataCheckRequestDTO requestDTO);
}
/**
* 数据检查工具产品化服务
*
* @author xxx
* @since xxx
* */
public abstract class AbstractDataCheckProductService implements DataCheckProductService {
/**
* 数据检查
* @param requestDTO 请求参数
* @return
* */
public <T> BaseResult<Long> dataCheck(DataCheckRequestDTO requestDTO){
try{
//1. 参数合法性检查
Pair<Boolean,String> paramCheckResult = commonParamCheck(requestDTO);
if(!paramCheckResult.getLeft()){
return BaseResult.ofFail(paramCheckResult.getRight());
}
//2. 创建导出任务
String fileName = createFileName(requestDTO);
RouteTaskRecordDO taskRecordDO = createTaskRecord(fileName, requestDTO.getUserName());
//3. 进行数据检查
List<T> resultList = Collections.synchronizedList(new ArrayList<>());
runDataCheck(resultList, requestDTO);
//4. 写入文件
String ossUrl = uploadToOSS(fileName,resultList);
//5. 更新任务为完成状态
updateRouteTask(taskRecordDO.getId(),DDportTaskStatus.FINISHED.intValue(), resultList.size()-1,"",ossUrl);
return BaseResult.ofSuccess(taskRecordDO.getId());
}catch (Exception e){
LogPrinter.errorLog("dataCheck-error, beanName="+getBeanName(),e);
return BaseResult.ofFail(e.getMessage());
}
}
/**
* 进行数据检查
* @param resultList 存放检查结果
* @param requestDTO 请求参数
* @return
* */
public abstract <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO);
}
/**
* 检查资源映射和编码映射一致
* @author xxx
* @since xxx
* */
public class CheckSupplierAndCodeMappingService extends AbstractDataCheckProductService{
public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
//自己的检查逻辑
}
}
/**
* 检查区域内落地配必须三级全覆盖
* @author xxx
* @since xxx
* */
public class CheckLandingCoverAreaService extends AbstractDataCheckProductService{
public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
//自己的检查逻辑
}
}
/**
* 检查资源映射和编码映射一致
* @author xxx
* @since xxx
* */
public class CheckAncPathNoServiceService extends AbstractDataCheckProductService{
public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
//自己的检查逻辑
}
}
简化了代码,每个工具只需要关心自己的核心检查逻辑,不需要关注前置和后置操作。
提高了扩展性,可以方便地增加新的检查工具。
统一的异常捕获和处理逻辑,子类有异常,尽管往外抛出。
CompareModeStrategy对外提供统一的结果处理接口doHandle,策略子类必须实现此接口。
SupplierAndCodeMappingStatisticsStrategy和SupplierAndCodeMappingDetailStrategy是检查配送资源和编码映射一致性的两种结果信息方式,前者为统计方式,后者为详细方式。
LandingCoverAreaStatisticsStrategy和LandingCoverAreaDetailStrategy是检查落地配覆盖范围的两种结果信息方式,前者为统计方式,后者为详细方式。
那AbstractCompareModeStrategy是干什么用的?它是一个抽象类,负责承接所有策略子类共用的一些方法。
/**
* 检查结果策略对外接口
* @author xxx
* @since xxx
* */
public interface CompareModeStrategy {
/**
* 具体操作
*
* @param list
* @param requestDTO
* @return 结果集
* */
<T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO);
}
/**
* 策略公共父类
*
* @author xxx
* @since xxx
* @apiNote 主要是将子类共用方法和成员抽离出来
* */
public abstract class AbstractCompareModeStrategy implements CompareModeStrategy {
//子类的共用方法,可以放在此类中
}
/**
* 检查落地配覆盖范围 详细信息 策略类
* @author xxx
* @since xxx
* */
public class LandingCoverAreaDetailStrategy extends AbstractCompareModeStrategy{
@Override
public <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){
List<T> resultList = new ArrayList<>();
//检查结果处理逻辑
return resultList;
}
}
/**
* 检查落地配覆盖范围 统计信息 策略类
* @author xxx
* @since xxx
* */
public class LandingCoverAreaStatisticsStrategy extends AbstractCompareModeStrategy{
@Override
public <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){
List<T> resultList = new ArrayList<>();
//检查结果处理逻辑
return resultList;
}
}
/**
* 检查配送资源和编码映射一致 详细信息 策略类
* @author xxx
* @since xxx
* */
public class SupplierAndCodeMappingDetailStrategy extends AbstractCompareModeStrategy{
@Override
public <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){
List<T> resultList = new ArrayList<>();
//检查结果处理逻辑
return resultList;
}
}
/**
* 检查配送资源和编码映射一致 统计信息 策略类
* @author xxx
* @since xxx
* */
public class SupplierAndCodeMappingStatisticsStrategy extends AbstractCompareModeStrategy{
@Override
public <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){
List<T> resultList = new ArrayList<>();
//检查结果处理逻辑
return resultList;
}
}
提高代码扩展性,后续增加别的结果格式或别的网络处理逻辑,可以在不修改其他策略的情况下直接新增。
提高代码可读性,取代了if...else,条理清晰。
不同系列采用不同的策略,策略与策略之间可以嵌套使用,形成策略的叠加效用。
模板方法模式中所用到的子类。
检查结果格式策略中所用到的子类。
不同网络处理策略中所用到的子类。
DataCheckProductFatory:由getDataCheckProductService方法根据输入参数决策使用哪个数据检查工具。
CompareModeStrategyFactory:用于决策使用哪种格式输出,因为将输出策略分为了2类(详细信息和统计信息),所以需要传入两个参数才能决定使用哪种策略。
DataCheckNetworkStrategyFactory:用于决策使用哪种网络处理策略,因为将策略分为了2类(4PL网络和其他网络),所以需要传入两个参数才能决定使用哪种策略。
/**
* 比对结果集方式
* @author xxx
* @since xxx
* */
public class CompareModeStrategyFactory {
/************************ 详细结果的bean **************************/
private LandingCoverAreaDetailStrategy landingCoverAreaDetailStrategy;
private SupplierAndCodeMappingDetailStrategy supplierAndCodeMappingDetailStrategy;
/************************ 统计结果的bean **************************/
private LandingCoverAreaStatisticsStrategy landingCoverAreaStatisticsStrategy;
private SupplierAndCodeMappingStatisticsStrategy supplierAndCodeMappingStatisticsStrategy;
/**
* 获取比对结果的策略
* */
public CompareModeStrategy getCompareModeStrategy(DataCheckProductEnum productEnum, DataCompareModeEnum modeEnum){
CompareModeStrategy compareModeStrategy = null;
switch (modeEnum){
case DETAIL_INFO:
compareModeStrategy = getDetailCompareModeStrategy(productEnum);
break;
case STATISTICS_INFO :
compareModeStrategy = getStatisticsCompareModeStrategy(productEnum);
break;
default:;
}
return compareModeStrategy;
}
/**
* 获取 信息信息 策略对象
* */
private CompareModeStrategy getDetailCompareModeStrategy(DataCheckProductEnum productEnum){
CompareModeStrategy compareModeStrategy = null;
switch (productEnum){
case CHECK_LANDING_COVER_AREA:
compareModeStrategy = landingCoverAreaDetailStrategy;
break;
case CHECK_SUPPLIER_AND_CODE_MAPPING:
compareModeStrategy = supplierAndCodeMappingDetailStrategy;
break;
default:;
}
return compareModeStrategy;
}
/**
* 获取 统计信息 策略对象
* */
private CompareModeStrategy getStatisticsCompareModeStrategy(DataCheckProductEnum productEnum){
CompareModeStrategy compareModeStrategy = null;
switch (productEnum){
case CHECK_LANDING_COVER_AREA:
compareModeStrategy = landingCoverAreaStatisticsStrategy;
break;
case CHECK_SUPPLIER_AND_CODE_MAPPING:
compareModeStrategy = supplierAndCodeMappingStatisticsStrategy;
break;
default:;
}
return compareModeStrategy;
}
}
便于bean的管理,所有的bean都在一处创建(或决策)。
条理清晰,便于阅读和维护。
@Service
public class CheckLandingCoverAreaService extends AbstractDataCheckProductService {
@Override
public <T> void runDataCheck(List<T> resultList, DataCheckRequestDTO requestDTO){
dataCheckUtils.parallelCheckByFromResCodes(requestDTO,requestDTO.getFromResCodeList(),fromResCode->{
ExpressNetworkQuery query = new ExpressNetworkQuery();
query.setNs(NssEnum.PUB.getId());
query.setStatus(StatusEnum.ENABLE.getId());
query.setGroupNameList(requestDTO.getGroupNameList());
query.setBrandCodeList(requestDTO.getBrandCodeList());
query.setFromResCode(fromResCode);
List<TmsMasterExpressNetworkDO> masterExpressNetworkDOS = tmsMasterExpressNetworkService.queryExpressNetworkTimeList(query);
startCompareWithAnc(resultList,requestDTO,masterExpressNetworkDOS,fromResCode,solutionCodeMap);
});
}
}
@Service
public class DataCheckUtils {
/**
* 并行处理每个仓
* @param requestDTO 请求参数
* @param fromResCodeList 需要检查的仓列表
* @param checkOperation 具体的业务处理逻辑
* */
public <T> void parallelCheckByFromResCodes(DataCheckRequestDTO requestDTO, List<String> fromResCodeList, Consumer<String> checkOperation){
List<CompletableFuture> futureList = Collections.synchronizedList(new ArrayList<>());
fromResCodeList.forEach(fromResCode->{
CompletableFuture future = CompletableFuture.runAsync(() -> {
try{
checkOperation.accept(fromResCode);
}catch (Exception e){
LogPrinter.errorLog("parallelCheckByFromResCodes-error, taskId="+requestDTO.getTaskId(),e);
recordErrorInfo(requestDTO.getTaskId(),e);
}
}, DATA_CHECK_THREAD_POOL);
futureList.add(future);
});
//等待所有线程结束
futureList.forEach(future->{
try{
future.get();
}catch (Exception e){
LogPrinter.errorLog("parallelCheckByFromResCodes-future-get-error",e);
}
});
}
}
统一收口多种不同的业务逻辑,统一做日志和异常处理。
减少重复代码,提高了代码质量。
可维护性较强。
将提升代码可读性、可扩展性和可维护性的意识注入到平时的项目中,便于自己,利于他人。如果项目紧急没时间考虑很多,希望之后有时间时能够改善和优化。
工作不仅是为了完成任务,更是提升自己的过程。能力要用将来进行时。
有道无术,术可成;有术无道,止于术
欢迎大家关注Java之道公众号
好文章,我在看❤️
评论
真高!比亚迪员工爆料比亚迪在越南的薪资水平:基本工资480万,全勤奖35万,交通补助20万,餐补110万,每周6天,每天10小时
上一篇:某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...对此,你怎么看?--完--PS:欢迎在留言区留下你的观点,一起讨论提高。如果今天的文章让你有新的启发,欢迎转发分享给更多人。全文完,感谢你的耐心阅读。如果你还想看到我的文章,请一定给本
开发者全社区
0
太敢穿了!透视纱裙!性感火辣的身材
绝了呀今天的厂花:吴宣仪1995年1月26日,吴宣仪出生于海南省海口市,中国内地流行乐女歌手、影视演员。2016年2月,吴宣仪随宇宙少女发行首张迷你专辑正式出道。2018年4月,她参加《创造101》综艺选秀,获得第二名,成功加入火箭少女101组合。吴宣仪的颜值一直备受称赞,她的五官立体精致,皮肤白皙
逆锋起笔
0
某大公司为逼迫员工离职,竟然把他的工位安排到厕所旁,没想到他直接开始记录领导的如厕时间,还发到公司大群...
上一篇:字节的跳动职级与薪资(2024年)我们与公司间的合作,宛如两艘船只在茫茫大海上相互依靠,共同抵御风浪,携手驶向成功的彼岸。然而,当航向开始产生分歧,或是波涛汹涌的风浪改变了我们的初衷,我们或许应当冷静地选择和平分手,而非在风雨中硬撑。最近,一位网友的遭遇引起了广大职场人的关注和热议。这位网友
开发者全社区
0
金融研究 | 使用Python测量关键审计事项的「信息含量」
Tips: 公众号推送后内容只能更改一次,且只能改20字符。如果内容出问题,或者想更新内容, 只能重复推送。为了更好的阅读体验,建议阅读本文博客版, 链接地址https://textdata.cn/blog/2023-01-13-information-content-of-critical-aud
大邓和他的Python
0
我看阿里的年终奖总算发了!
到4月底了,这两天看朋友圈,发现阿里的年终奖终于发了,问了问老同学,也从网上检索了不少信息,基本搞清楚了阿里今年的年终奖情况。近来来阿里一些集团对绩效等级做了较大的调整,以前的旧绩效系统中,绩效分为3.25、3.5、3.75、4和5五个等级,其中4和5是较高绩效等级,较少见。而且之前3.5绩效内部划
公子龙
0
一女子与一男子在阳台上打扑克,被邻居偷拍后...
近日网络上又发生了一起疑似黄色谣言的事件:一女子与一男子在阳台上打扑克,被邻居偷拍后上传到网上,引发广泛舆论讨论。根据网传视频显示,一名穿着吊带睡衣的女子与一名光着上身的男性在阳台上交谈,随后开始打起扑克牌。这一幕被邻居拍下并上传至网络后,引发了许多网友的关注和猜测,其中大部分涉及到了不当的假设。当
逆锋起笔
0
CVPR 2024|大视觉模型的开山之作!无需任何语言数据即可打造大视觉模型
↑ 点击蓝字 关注极市平台作者丨科技猛兽编辑丨极市平台极市导读 本文提出一种序列建模 (sequential modeling) 的方法,不使用任何语言数据,训练大视觉模型。>>加入极市CV技术交流群,走在计算机视觉的最前沿本文目录1 序列建模打造大视觉模型(来自 U
极市平台
1
金融研究(更新) | 使用Python构建关键审计事项的「信息含量」
Tips: 公众号推送后内容只能更改一次,且只能改20字符。如果内容出问题,或者想更新内容, 只能重复推送。为了更好的阅读体验,建议阅读本文博客版, 链接地址https://textdata.cn/blog/2023-01-13-information-content-of-critical-aud
大邓和他的Python
0