設(shè)計(jì)模式在業(yè)務(wù)系統(tǒng)中的應(yīng)用
本文的重點(diǎn)在于說明工作中所使用的設(shè)計(jì)模式,為了能夠更好的理解設(shè)計(jì)模式,首先簡單介紹一下業(yè)務(wù)場景。使用設(shè)計(jì)模式,可以簡化代碼、提高擴(kuò)展性、可維護(hù)性和復(fù)用性。有哪些設(shè)計(jì)模式,這里就不再介紹了,網(wǎng)上很多,本文只介紹所用到設(shè)計(jì)模式。
一 線路檢查工具
1 意義
為什么需要線路檢查工具呢,有以下幾個(gè)方面的原因:
每逢大促都需要進(jìn)行各網(wǎng)絡(luò)和各行業(yè)的線路調(diào)整,調(diào)整完成之后,是否得到期望狀態(tài),需要檢查確認(rèn)。
上下游應(yīng)用之間數(shù)據(jù)的一致性檢查,如果存在不一致,可能會(huì)在訂單履行時(shí)造成卡單。
有些問題發(fā)生后,業(yè)務(wù)同學(xué)需要全面檢查一遍線路數(shù)據(jù),判斷是否符合預(yù)期。
各領(lǐng)域之間的數(shù)據(jù)變更缺乏聯(lián)動(dòng)性,導(dǎo)致資源和線路出現(xiàn)不一致。
以前每次大促,都是技術(shù)同學(xué)現(xiàn)場編寫代碼撈數(shù)據(jù)給到業(yè)務(wù)同學(xué),而且因?yàn)槿藛T流動(dòng)性較大,代碼可復(fù)用性較低,導(dǎo)致重復(fù)勞動(dòng)。產(chǎn)品化后,可以方便地傳承下去,避免不必要的重復(fù)勞動(dòng)。
每次因?yàn)闀r(shí)間緊急,現(xiàn)場寫的代碼都比較簡單,經(jīng)常是直接將數(shù)據(jù)打印到標(biāo)準(zhǔn)輸出,然后復(fù)制出來,人工拆分轉(zhuǎn)成Excel格式;這樣的過程要進(jìn)行多次,占用太多技術(shù)同學(xué)的時(shí)間。產(chǎn)品化后,解放了技術(shù)同學(xué),業(yè)務(wù)同學(xué)可以自己在頁面操作。
很多數(shù)據(jù)檢查,是每次大促都會(huì)進(jìn)行的,業(yè)務(wù)同學(xué)與技術(shù)同學(xué)之間來回溝通的成本較高。產(chǎn)品化后,可以避免這些耗時(shí)耗力的溝通,大家可以把更多的時(shí)間放在其他的大促保障工作上。
時(shí)效對齊檢查:確保履行分單正常。
弱控線路與表達(dá)網(wǎng)絡(luò)一致性:確保履行和路由不會(huì)因?yàn)榫€路缺失而卡單。
資源映射和編碼映射一致:前者是表達(dá)線路時(shí)所用,后者是訂單履約時(shí)所用,確保表達(dá)和履約能夠一致。
檢查線路數(shù)量:統(tǒng)計(jì)現(xiàn)存線路的情況。


commonParamCheck方法:進(jìn)行參數(shù)合法性檢查,不合法的情況下,直接返回。
createFileName方法:創(chuàng)建文件名稱。
createTaskRecord方法:創(chuàng)建檢查任務(wù)。
runDataCheck方法:進(jìn)行數(shù)據(jù)檢查,這是一個(gè)抽象方法,所有檢查工具都要實(shí)現(xiàn)此方法,以實(shí)現(xiàn)自己的邏輯。
uploadToOSS方法:將檢查結(jié)果上傳到OSS,便于下載。
updateRouteTask方法:結(jié)束時(shí)更新任務(wù)為完成。
/*** 數(shù)據(jù)檢查工具產(chǎn)品化對外服務(wù)接口* @author xxx* @since xxx* */public interface DataCheckProductService {/*** 數(shù)據(jù)檢查* @param requestDTO 請求參數(shù)* */<T> BaseResult<Long> dataCheck(DataCheckRequestDTO requestDTO);}/*** 數(shù)據(jù)檢查工具產(chǎn)品化服務(wù)** @author xxx* @since xxx* */public abstract class AbstractDataCheckProductService implements DataCheckProductService {/*** 數(shù)據(jù)檢查* @param requestDTO 請求參數(shù)* @return* */public <T> BaseResult<Long> dataCheck(DataCheckRequestDTO requestDTO){try{//1. 參數(shù)合法性檢查Pair<Boolean,String> paramCheckResult = commonParamCheck(requestDTO);if(!paramCheckResult.getLeft()){return BaseResult.ofFail(paramCheckResult.getRight());}//2. 創(chuàng)建導(dǎo)出任務(wù)String fileName = createFileName(requestDTO);RouteTaskRecordDO taskRecordDO = createTaskRecord(fileName, requestDTO.getUserName());//3. 進(jìn)行數(shù)據(jù)檢查List<T> resultList = Collections.synchronizedList(new ArrayList<>());runDataCheck(resultList, requestDTO);//4. 寫入文件String ossUrl = uploadToOSS(fileName,resultList);//5. 更新任務(wù)為完成狀態(tài)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());}}/*** 進(jìn)行數(shù)據(jù)檢查* @param resultList 存放檢查結(jié)果* @param requestDTO 請求參數(shù)* @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){//自己的檢查邏輯}}/*** 檢查區(qū)域內(nèi)落地配必須三級全覆蓋* @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){//自己的檢查邏輯}}
簡化了代碼,每個(gè)工具只需要關(guān)心自己的核心檢查邏輯,不需要關(guān)注前置和后置操作。
提高了擴(kuò)展性,可以方便地增加新的檢查工具。
統(tǒng)一的異常捕獲和處理邏輯,子類有異常,盡管往外拋出。


CompareModeStrategy對外提供統(tǒng)一的結(jié)果處理接口doHandle,策略子類必須實(shí)現(xiàn)此接口。
SupplierAndCodeMappingStatisticsStrategy和SupplierAndCodeMappingDetailStrategy是檢查配送資源和編碼映射一致性的兩種結(jié)果信息方式,前者為統(tǒng)計(jì)方式,后者為詳細(xì)方式。
LandingCoverAreaStatisticsStrategy和LandingCoverAreaDetailStrategy是檢查落地配覆蓋范圍的兩種結(jié)果信息方式,前者為統(tǒng)計(jì)方式,后者為詳細(xì)方式。
那AbstractCompareModeStrategy是干什么用的?它是一個(gè)抽象類,負(fù)責(zé)承接所有策略子類共用的一些方法。
/*** 檢查結(jié)果策略對外接口* @author xxx* @since xxx* */public interface CompareModeStrategy {/*** 具體操作** @param list* @param requestDTO* @return 結(jié)果集* */<T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO);}/*** 策略公共父類** @author xxx* @since xxx* @apiNote 主要是將子類共用方法和成員抽離出來* */public abstract class AbstractCompareModeStrategy implements CompareModeStrategy {//子類的共用方法,可以放在此類中}/*** 檢查落地配覆蓋范圍 詳細(xì)信息 策略類* @author xxx* @since xxx* */public class LandingCoverAreaDetailStrategy extends AbstractCompareModeStrategy{@Overridepublic <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){List<T> resultList = new ArrayList<>();//檢查結(jié)果處理邏輯return resultList;}}/*** 檢查落地配覆蓋范圍 統(tǒng)計(jì)信息 策略類* @author xxx* @since xxx* */public class LandingCoverAreaStatisticsStrategy extends AbstractCompareModeStrategy{@Overridepublic <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){List<T> resultList = new ArrayList<>();//檢查結(jié)果處理邏輯return resultList;}}/*** 檢查配送資源和編碼映射一致 詳細(xì)信息 策略類* @author xxx* @since xxx* */public class SupplierAndCodeMappingDetailStrategy extends AbstractCompareModeStrategy{@Overridepublic <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){List<T> resultList = new ArrayList<>();//檢查結(jié)果處理邏輯return resultList;}}/*** 檢查配送資源和編碼映射一致 統(tǒng)計(jì)信息 策略類* @author xxx* @since xxx* */public class SupplierAndCodeMappingStatisticsStrategy extends AbstractCompareModeStrategy{@Overridepublic <T> List<T> doHandle(List<CompareBO> list, DataCheckRequestDTO requestDTO){List<T> resultList = new ArrayList<>();//檢查結(jié)果處理邏輯return resultList;}}

提高代碼擴(kuò)展性,后續(xù)增加別的結(jié)果格式或別的網(wǎng)絡(luò)處理邏輯,可以在不修改其他策略的情況下直接新增。
提高代碼可讀性,取代了if...else,條理清晰。
不同系列采用不同的策略,策略與策略之間可以嵌套使用,形成策略的疊加效用。
模板方法模式中所用到的子類。
檢查結(jié)果格式策略中所用到的子類。
不同網(wǎng)絡(luò)處理策略中所用到的子類。
DataCheckProductFatory:由getDataCheckProductService方法根據(jù)輸入?yún)?shù)決策使用哪個(gè)數(shù)據(jù)檢查工具。
CompareModeStrategyFactory:用于決策使用哪種格式輸出,因?yàn)閷⑤敵霾呗苑譃榱?類(詳細(xì)信息和統(tǒng)計(jì)信息),所以需要傳入兩個(gè)參數(shù)才能決定使用哪種策略。
DataCheckNetworkStrategyFactory:用于決策使用哪種網(wǎng)絡(luò)處理策略,因?yàn)閷⒉呗苑譃榱?類(4PL網(wǎng)絡(luò)和其他網(wǎng)絡(luò)),所以需要傳入兩個(gè)參數(shù)才能決定使用哪種策略。



/*** 比對結(jié)果集方式* @author xxx* @since xxx* */public class CompareModeStrategyFactory {/************************ 詳細(xì)結(jié)果的bean **************************/private LandingCoverAreaDetailStrategy landingCoverAreaDetailStrategy;private SupplierAndCodeMappingDetailStrategy supplierAndCodeMappingDetailStrategy;/************************ 統(tǒng)計(jì)結(jié)果的bean **************************/private LandingCoverAreaStatisticsStrategy landingCoverAreaStatisticsStrategy;private SupplierAndCodeMappingStatisticsStrategy supplierAndCodeMappingStatisticsStrategy;/*** 獲取比對結(jié)果的策略* */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;}/*** 獲取 統(tǒng)計(jì)信息 策略對象* */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都在一處創(chuàng)建(或決策)。
條理清晰,便于閱讀和維護(hù)。
@Servicepublic class CheckLandingCoverAreaService extends AbstractDataCheckProductService {@Overridepublic <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);});}}@Servicepublic class DataCheckUtils {/*** 并行處理每個(gè)倉* @param requestDTO 請求參數(shù)* @param fromResCodeList 需要檢查的倉列表* @param checkOperation 具體的業(yè)務(wù)處理邏輯* */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);});//等待所有線程結(jié)束futureList.forEach(future->{try{future.get();}catch (Exception e){LogPrinter.errorLog("parallelCheckByFromResCodes-future-get-error",e);}});}}
統(tǒng)一收口多種不同的業(yè)務(wù)邏輯,統(tǒng)一做日志和異常處理。
減少重復(fù)代碼,提高了代碼質(zhì)量。
可維護(hù)性較強(qiáng)。
將提升代碼可讀性、可擴(kuò)展性和可維護(hù)性的意識注入到平時(shí)的項(xiàng)目中,便于自己,利于他人。如果項(xiàng)目緊急沒時(shí)間考慮很多,希望之后有時(shí)間時(shí)能夠改善和優(yōu)化。
工作不僅是為了完成任務(wù),更是提升自己的過程。能力要用將來進(jìn)行時(shí)。
有道無術(shù),術(shù)可成;有術(shù)無道,止于術(shù)
歡迎大家關(guān)注Java之道公眾號
好文章,我在看??
評論
圖片
表情
