引言:很久沒有更新了,主要是工作忙奋姿。最近逸尖,工作中一個子系統(tǒng)升級古沥,把之前不易擴展的缺點給改進了一下,主要是運用了幾個設(shè)計模式進行稍微改造了一下娇跟。
1.項目背景
在公司的一個實際項目中岩齿,需要做一個第三方公司(以下簡稱GMG)的系統(tǒng)集成工作,把該公司的一些訂單數(shù)據(jù)集成到自己公司平臺下苞俘,各個訂單具有一些共性盹沈,但是也有其特有的特征。 經(jīng)過設(shè)計苗胀,目前我把訂單分為POLICY和BOB類型(暫且這么說吧襟诸,反正就是一種訂單類型,大家參照著看就OK)基协。
在訂單數(shù)據(jù)集成到公司平臺前歌亲,需要對訂單數(shù)據(jù)進行一些必要的業(yè)務(wù)邏輯校驗操作,并且每個訂單都有自己的校驗邏輯(包含公共的校驗邏輯)澜驮。 本節(jié)介紹的便是整個訂單集成系統(tǒng)中的校驗邏輯在綜合利用設(shè)計模式的基礎(chǔ)上進行架構(gòu)設(shè)計陷揪。
2.校驗邏輯
本校驗邏輯主要分為四個部分:
- 校驗文件名稱(RequestValidator.validateFileInfo)
- 校驗文件內(nèi)容中的概要部分(RequestValidator.validateSummary)
- 校驗文件內(nèi)容中的列名稱(RequestValidator.validateHeaders)
- 校驗文件內(nèi)容中的明細(RequestValidator.validateDetails)
其實上面的RequestValidator的實現(xiàn)邏輯最后都是委托給RequestValidationFacade這個門面類進行相應的校驗操作。
3.實現(xiàn)細節(jié)
3.1 domain介紹
主要分為RequestFile和RequestDetail兩個domain,RequestFile接收泛型的類型(即RequestFile), 使得其子類能夠自動識別相應的RequestDetail的子類杂穷。RequestFile為抽象類悍缠,定義了以下抽象方法,由子類實現(xiàn):
//由子類實現(xiàn)具體的獲取文件明細內(nèi)容
public abstract List<T> getRequestDetails();
//由子類實現(xiàn)具體的獲取workflow的值
public abstract WorkflowEnum getProcessWorkFlow();
//由子類實現(xiàn)文件列字段名列表
public abstract String[] getDetailHeaders();
RequestDetail及其子類就是workflow對應文件的明細內(nèi)容耐量。
3.2 WorkflowEnum枚舉策略
本例中如下規(guī)定:
- workflow為WorkflowEnum.POLICY對應文件名為:csync_policy_yyyyMMdd_HHmmss_count.txt
- workflow為WorkflowEnum.BOB對應文件名為:csync_bob_integration_yyyyMMdd_HHmmss_count.txt
以上校驗邏輯在AbstractRequestValidation類相應的子類中實現(xiàn)(validateFileName方法)飞蚓,其實這個枚舉貫穿整個校驗組件,它就是一個針對每個業(yè)務(wù)流程定義的一個枚舉策略廊蜒。
3.3 涉及到的設(shè)計模式實現(xiàn)思路
3.3.1 門面模式
在客戶端調(diào)用程序中趴拧,采用門面模式進行統(tǒng)一的入口(門面模式講究的是脫離具體的業(yè)務(wù)邏輯代碼)。門面模式封裝的結(jié)果就是避免高層模塊深入子系統(tǒng)內(nèi)部山叮,同時提供系統(tǒng)的高內(nèi)聚著榴、低耦合的特性。
此案例中屁倔,門面類為RequestValidationFacade脑又,然后各個門面方法的參數(shù)均為抽象類RequestFile,通過RequestFile->getProcessWorkFlow()決定調(diào)用AbstractRequestValidation中的哪個子類。 AbstractRequestValidation類構(gòu)造方法中定義了如下邏輯:
requestValidationHandlerMap.put(this.accessWorkflow(),this.accessBeanName());
把子類中Spring自動注入的實體bean緩存到requestValidationHandlerMap中问麸,key即為WorkflowEnum枚舉值往衷,value為spring bean name, 然后在門面類中可以通過對應的枚舉值取得BeanName,進而得到AbstractRequestValidation相應的子類對象口叙,進行相應的校驗操作炼绘。
注:這邊動態(tài)調(diào)用到AbstractRequestValidation相應的子類對象,其實也是隱藏著【策略模式】的影子妄田。
類圖如下:
3.3.2 模版方法模式
在具體的校驗邏輯中,用到核心設(shè)計模式便是模版方法模式驮捍,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ù)疟呐,由子類實現(xiàn)即可。類圖如下圖所示:
3.3.3 責任鏈模式
在AbstractRequestValidation抽象類中有個抽象方法validateFileDetails东且,校驗的是文件的明細內(nèi)容中的相應業(yè)務(wù)規(guī)則,此為核心校驗, 較為復雜扣讼,而且針對每個業(yè)務(wù)流程猜极,其校驗邏輯相差較大,在此處色查,利用了責任鏈模式進行處理薯演。
Validator為校驗器的父接口,包含兩個泛型參數(shù)(即:<R extends RequestDetail,F extends RequestFile>)秧了,其實現(xiàn)類可以方便的轉(zhuǎn)換需要校驗的文件明細跨扮。
String doValidate(R detail, F file, ValidatorChain chain) throws BusinessValidationException;
該方法含有一個ValidatorChain參數(shù),就自然而然的為該校驗器形成一個鏈條提供便利條件验毡。
ValidatorChain為校驗器鏈衡创,含有兩個接口方法:
String doValidate(T requestDetail, F requestFile) throws BusinessValidationException;
ValidatorChain addValidator(Validator validator, WorkflowEnum workflowId);
該處有一個addValidator方法,為ValidatorChain對象添加校驗器的方法晶通,返回本身璃氢。對應于每個業(yè)務(wù)流程需要哪些校驗器就在此實現(xiàn)即可(即AbstractRequestValidation的子類方法validateFileDetails)。
類圖如下圖所示:
3.3.4 策略模式
如果單單從上面的校驗器實現(xiàn)上來看狮辽,如果需要增加一個校驗器一也,就需要在AbstractRequestValidation的子類方法validateFileDetails中添加,然后進行相應的校驗操作隘竭。這樣就會非常的麻煩塘秦,沒有做到真正的解耦。 此時动看,策略模式就發(fā)揮到了可以動態(tài)選擇某種校驗策略的作用(Validator的實現(xiàn)類就是一個具體的校驗策略)尊剔。
AbstractValidatorHandler抽象類持有FileDetailValidatorChain類的對象,并且實現(xiàn)累Spring的一個接口ApplicationListener(是為了Spring容器啟動完成的時候自動把相應的校驗器加入到校驗器鏈中)菱皆。 核心就是WorkflowEnum這個策略枚舉的作用须误,在子類可以動態(tài)的取得相應的校驗器對象挨稿。
根據(jù)子類提供需要的校驗器所在的包名列表和不需要的校驗器列表,動態(tài)配置出需要的校驗器鏈表京痢。核心實現(xiàn)邏輯如下:
private void addValidators() {
List<Class<? extends Validator>> 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());
});
}
具體實現(xiàn)可以參考github代碼即可奶甘。
該類含有以下幾個抽象方法:
protected abstract WorkflowEnum getWorkflowId();
/**
* the package need to be added the validators
* @return
*/
protected abstract Set<String> getBasePackages();
/**
* the classes need to be excluded
* @return
*/
protected abstract Set<Class> excludeClasses();