摘要:此案例中,門面類為,然后各個(gè)門面方法的參數(shù)均為抽象類,通過決定調(diào)用中的哪個(gè)子類。抽象類持有類的對象,并且實(shí)現(xiàn)累的一個(gè)接口是為了容器啟動完成的時(shí)候自動把相應(yīng)的校驗(yàn)器加入到校驗(yàn)器鏈中。
引言:很久沒有更新了,主要是工作忙。最近,工作中一個(gè)子系統(tǒng)升級,把之前不易擴(kuò)展的缺點(diǎn)給改進(jìn)了一下,主要是運(yùn)用了幾個(gè)設(shè)計(jì)模式進(jìn)行稍微改造了一下。1.項(xiàng)目背景
本文也同步發(fā)布至簡書,地址: https://www.jianshu.com/p/962...
在公司的一個(gè)實(shí)際項(xiàng)目中,需要做一個(gè)第三方公司(以下簡稱GMG)的系統(tǒng)集成工作,把該公司的一些訂單數(shù)據(jù)集成到自己公司平臺下,各個(gè)訂單具有一些共性,但是也有其特有的特征。 經(jīng)過設(shè)計(jì),目前我把訂單分為POLICY和BOB類型(暫且這么說吧,反正就是一種訂單類型,大家參照著看就OK)。
在訂單數(shù)據(jù)集成到公司平臺前,需要對訂單數(shù)據(jù)進(jìn)行一些必要的業(yè)務(wù)邏輯校驗(yàn)操作,并且每個(gè)訂單都有自己的校驗(yàn)邏輯(包含公共的校驗(yàn)邏輯)。 本節(jié)介紹的便是整個(gè)訂單集成系統(tǒng)中的校驗(yàn)邏輯在綜合利用設(shè)計(jì)模式的基礎(chǔ)上進(jìn)行架構(gòu)設(shè)計(jì)。
2.校驗(yàn)邏輯本校驗(yàn)邏輯主要分為四個(gè)部分:
校驗(yàn)文件名稱(RequestValidator.validateFileInfo)
校驗(yàn)文件內(nèi)容中的概要部分(RequestValidator.validateSummary)
校驗(yàn)文件內(nèi)容中的列名稱(RequestValidator.validateHeaders)
校驗(yàn)文件內(nèi)容中的明細(xì)(RequestValidator.validateDetails)
其實(shí)上面的RequestValidator的實(shí)現(xiàn)邏輯最后都是委托給RequestValidationFacade這個(gè)門面類進(jìn)行相應(yīng)的校驗(yàn)操作。
3.實(shí)現(xiàn)細(xì)節(jié) 3.1 domain介紹主要分為RequestFile和RequestDetail兩個(gè)domain,RequestFile接收泛型的類型(即RequestFile), 使得其子類能夠自動識別相應(yīng)的RequestDetail的子類。RequestFile為抽象類,定義了以下抽象方法,由子類實(shí)現(xiàn):
//由子類實(shí)現(xiàn)具體的獲取文件明細(xì)內(nèi)容 public abstract ListgetRequestDetails(); //由子類實(shí)現(xiàn)具體的獲取workflow的值 public abstract WorkflowEnum getProcessWorkFlow(); //由子類實(shí)現(xiàn)文件列字段名列表 public abstract String[] getDetailHeaders();
RequestDetail及其子類就是workflow對應(yīng)文件的明細(xì)內(nèi)容。
3.2 WorkflowEnum枚舉策略本例中如下規(guī)定:
workflow為WorkflowEnum.POLICY對應(yīng)文件名為:csync_policy_yyyyMMdd_HHmmss_count.txt
workflow為WorkflowEnum.BOB對應(yīng)文件名為:csync_bob_integration_yyyyMMdd_HHmmss_count.txt
以上校驗(yàn)邏輯在AbstractRequestValidation類相應(yīng)的子類中實(shí)現(xiàn)(validateFileName方法),其實(shí)這個(gè)枚舉貫穿整個(gè)校驗(yàn)組件,它就是一個(gè)針對每個(gè)業(yè)務(wù)流程定義的一個(gè)枚舉策略。
3.3 涉及到的設(shè)計(jì)模式實(shí)現(xiàn)思路 3.3.1 門面模式在客戶端調(diào)用程序中,采用門面模式進(jìn)行統(tǒng)一的入口(門面模式講究的是脫離具體的業(yè)務(wù)邏輯代碼)。門面模式封裝的結(jié)果就是避免高層模塊深入子系統(tǒng)內(nèi)部,同時(shí)提供系統(tǒng)的高內(nèi)聚、低耦合的特性。
此案例中,門面類為RequestValidationFacade,然后各個(gè)門面方法的參數(shù)均為抽象類RequestFile,通過RequestFile->getProcessWorkFlow()決定調(diào)用AbstractRequestValidation中的哪個(gè)子類。 AbstractRequestValidation類構(gòu)造方法中定義了如下邏輯:
requestValidationHandlerMap.put(this.accessWorkflow(),this.accessBeanName());
把子類中Spring自動注入的實(shí)體bean緩存到requestValidationHandlerMap中,key即為WorkflowEnum枚舉值,value為spring bean name, 然后在門面類中可以通過對應(yīng)的枚舉值取得BeanName,進(jìn)而得到AbstractRequestValidation相應(yīng)的子類對象,進(jìn)行相應(yīng)的校驗(yàn)操作。
注:這邊動態(tài)調(diào)用到AbstractRequestValidation相應(yīng)的子類對象,其實(shí)也是隱藏著【策略模式】的影子。
類圖如下:
在具體的校驗(yàn)邏輯中,用到核心設(shè)計(jì)模式便是模版方法模式,AbstractRequestValidation抽象類中定義了以下抽象方法:
/** * validate the file details * @param errMsg * @param requestFile * @return */ protected abstract StringBuilder validateFileDetails(StringBuilder errMsg,RequestFile requestFile); /** * validate the file name * @param fileName * @return */ protected abstract String validateFileName(String fileName); /** * return the current CSYNC_UPDATE_WORKFLOW.UPDATE_WORKFLOW_ID * @return */ protected abstract WorkflowEnum accessWorkflow(); /** * return the current file name"s format ,such as: csync_policy_yyyyMMdd_HHmmss_count.txt * @return */ protected abstract String accessFileNameFormat(); /** * return the subclass"s spring bean name * @return */ protected abstract String accessBeanName();
以上抽象方法就類似我們常說的鉤子函數(shù),由子類實(shí)現(xiàn)即可。類圖如下圖所示:
在AbstractRequestValidation抽象類中有個(gè)抽象方法validateFileDetails,校驗(yàn)的是文件的明細(xì)內(nèi)容中的相應(yīng)業(yè)務(wù)規(guī)則,此為核心校驗(yàn), 較為復(fù)雜,而且針對每個(gè)業(yè)務(wù)流程,其校驗(yàn)邏輯相差較大,在此處,利用了責(zé)任鏈模式進(jìn)行處理。
Validator為校驗(yàn)器的父接口,包含兩個(gè)泛型參數(shù)(即:
String doValidate(R detail, F file, ValidatorChain chain) throws BusinessValidationException;
該方法含有一個(gè)ValidatorChain參數(shù),就自然而然的為該校驗(yàn)器形成一個(gè)鏈條提供便利條件。
ValidatorChain為校驗(yàn)器鏈,含有兩個(gè)接口方法:
String doValidate(T requestDetail, F requestFile) throws BusinessValidationException; ValidatorChain addValidator(Validator validator, WorkflowEnum workflowId);
該處有一個(gè)addValidator方法,為ValidatorChain對象添加校驗(yàn)器的方法,返回本身。對應(yīng)于每個(gè)業(yè)務(wù)流程需要哪些校驗(yàn)器就在此實(shí)現(xiàn)即可(即AbstractRequestValidation的子類方法validateFileDetails)。
類圖如下圖所示:
如果單單從上面的校驗(yàn)器實(shí)現(xiàn)上來看,如果需要增加一個(gè)校驗(yàn)器,就需要在AbstractRequestValidation的子類方法validateFileDetails中添加,然后進(jìn)行相應(yīng)的校驗(yàn)操作。這樣就會非常的麻煩,沒有做到真正的解耦。 此時(shí),策略模式就發(fā)揮到了可以動態(tài)選擇某種校驗(yàn)策略的作用(Validator的實(shí)現(xiàn)類就是一個(gè)具體的校驗(yàn)策略)。
AbstractValidatorHandler抽象類持有FileDetailValidatorChain類的對象,并且實(shí)現(xiàn)累Spring的一個(gè)接口ApplicationListener(是為了Spring容器啟動完成的時(shí)候自動把相應(yīng)的校驗(yàn)器加入到校驗(yàn)器鏈中)。 核心就是WorkflowEnum這個(gè)策略枚舉的作用,在子類可以動態(tài)的取得相應(yīng)的校驗(yàn)器對象。
根據(jù)子類提供需要的校驗(yàn)器所在的包名列表和不需要的校驗(yàn)器列表,動態(tài)配置出需要的校驗(yàn)器鏈表。核心實(shí)現(xiàn)邏輯如下:
private void addValidators() { List> validators = getValidators(); validators.forEach((validator) -> { String simpleName = validator.getSimpleName(); String beanName = simpleName.substring(0, 1).toLowerCase() + simpleName.substring(1); LOGGER.info("Added validator:{},spring bean name is:{}",simpleName,beanName); Validator validatorInstance = ApplicationUtil.getApplicationContext().getBean(beanName,validator); fileDetailValidatorChain.addValidator(validatorInstance,getWorkflowId()); }); }
具體實(shí)現(xiàn)可以參考github代碼即可。
該類含有以下幾個(gè)抽象方法:
protected abstract WorkflowEnum getWorkflowId(); /** * the package need to be added the validators * @return */ protected abstract SetgetBasePackages(); /** * the classes need to be excluded * @return */ protected abstract Set excludeClasses();
事例代碼地址:https://github.com/landy8530/...
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/74532.html
摘要:注解方式優(yōu)點(diǎn)使用注解方式可以極大的減少使用模版方法模式帶來的擴(kuò)展時(shí)需要繼承模版類的弊端,工廠注解的方式可以無需關(guān)心其他業(yè)務(wù)類的實(shí)現(xiàn),而且減少了類膨脹的風(fēng)險(xiǎn)。 在上一篇文章Java設(shè)計(jì)模式綜合運(yùn)用(門面+模版方法+責(zé)任鏈+策略)中,筆者寫了一篇門面模式、模版方法、責(zé)任鏈跟策略模式的綜合運(yùn)用的事例文章,但是后來筆者發(fā)現(xiàn),在實(shí)現(xiàn)策略模式的實(shí)現(xiàn)上,發(fā)現(xiàn)了一個(gè)弊端:那就是如果在后續(xù)業(yè)務(wù)發(fā)展中,需...
摘要:責(zé)任鏈模式的具體運(yùn)用以及原理請參見筆者責(zé)任鏈模式改進(jìn)方式引入適配器模式關(guān)于接口適配器模式原理以及使用場景請參見筆者適配器模式。 1 責(zé)任鏈模式現(xiàn)存缺點(diǎn) 由于責(zé)任鏈大多數(shù)都是不純的情況,本案例中,只要校驗(yàn)失敗就直接返回,不繼續(xù)處理接下去責(zé)任鏈中的其他校驗(yàn)邏輯了,故而出現(xiàn)如果某個(gè)部分邏輯是要由多個(gè)校驗(yàn)器組成一個(gè)整理的校驗(yàn)邏輯的話,則此責(zé)任鏈模式則顯現(xiàn)出了它的不足之處了。(責(zé)任鏈模式的具體運(yùn)...
摘要:當(dāng)然,除了讓我們顯得更加專業(yè)之外,在自己所學(xué)習(xí)或者工作的項(xiàng)目中,適當(dāng)合理的使用設(shè)計(jì)模式,能夠給項(xiàng)目帶來很大的好處。 簡單說兩句 本文首發(fā)公眾號【一名打字員】 對不住各位老鐵了,年前說好要更幾波JAVA的東西,又偷懶了,沒辦法,在這里用小錘錘偷偷錘了自己幾下。由于工作原因,更新時(shí)間不定,各位老鐵有問題可以私聊我哈。 對于初學(xué)者或者是正在向中高級的Java程序猿(打字員)來說,時(shí)刻梳理自己...
摘要:能夠協(xié)調(diào)調(diào)用者和被調(diào)用者,能夠在一定程度上降低系統(tǒng)的耦合性。特點(diǎn)低耦合性,獨(dú)立性好,安全性應(yīng)用客戶訪問不到或者被訪問者希望隱藏自己,所以通過代理來訪問自己。 我們接著上面的幾種模式繼續(xù)講: 4、組合模式 將對象組合成樹形結(jié)構(gòu)表示部分-整體的層次結(jié)構(gòu)。 特點(diǎn):靈活性強(qiáng) 應(yīng)用:對象的部分-整體的層次結(jié)構(gòu),模糊組合對象和簡單對象處理問題 代碼實(shí)現(xiàn) /** 組合模式* *///繼承模式clas...
摘要:抽象工廠模式是為了處理對象具有等級結(jié)構(gòu)以及對象族的問題。單例設(shè)計(jì)模式單例模式確保某一個(gè)類只有一個(gè)實(shí)例,而且自行實(shí)例化并向整個(gè)系統(tǒng)提供這個(gè)實(shí)例,這個(gè)類成為單例類。 導(dǎo)語:設(shè)計(jì)模式是無數(shù)碼農(nóng)前人在實(shí)際的生產(chǎn)項(xiàng)目中經(jīng)過不斷的踩坑、爬坑、修坑的經(jīng)歷總結(jié)出來的經(jīng)驗(yàn)教訓(xùn),經(jīng)過抽象之后表達(dá)成的概念。能夠幫助后來的設(shè)計(jì)者避免重復(fù)同樣的錯誤或者彎路。我也抽空整理了一下設(shè)計(jì)模式,用自己的話總結(jié)了一下,自認(rèn)...
閱讀 907·2021-09-22 15:17
閱讀 1936·2021-09-22 15:06
閱讀 2224·2021-09-08 09:35
閱讀 5113·2021-09-01 11:43
閱讀 3485·2019-08-30 15:55
閱讀 2159·2019-08-30 12:48
閱讀 3157·2019-08-30 12:45
閱讀 1791·2019-08-29 17:31