模板方法模式介绍与示例
目錄
一、模板方法模式簡(jiǎn)介
二、代碼示例
?三、總結(jié)
一、模板方法模式簡(jiǎn)介
模板方法模式的核心設(shè)計(jì)思路是通過(guò)在抽象類(lèi)中公開(kāi)定義抽象方法的執(zhí)行順序,并將抽象方法的設(shè)定為只有子類(lèi)去實(shí)現(xiàn),但不設(shè)計(jì)獨(dú)立的訪(fǎng)問(wèn)方法。即子類(lèi)實(shí)現(xiàn)的抽象方法不能被其它類(lèi)訪(fǎng)問(wèn),所有抽象方法的執(zhí)行順序邏輯由抽象類(lèi)中的公開(kāi)方法進(jìn)行控制。
解決的問(wèn)題:系統(tǒng)中一些業(yè)務(wù)場(chǎng)景的方法能夠通用,每一個(gè)子類(lèi)卻都需要重新實(shí)現(xiàn)這一方法。
何時(shí)使用:有一些通用實(shí)現(xiàn)方法的時(shí)候就可以使用。
使用場(chǎng)景: 1、有多個(gè)子類(lèi)共有的方法,且邏輯相同。 2、重要或復(fù)雜的方法考慮作為模板方法。
二、代碼示例
首先我們先大概看下業(yè)務(wù)模型:假設(shè)我們現(xiàn)在有導(dǎo)入excel表格的功能,但是導(dǎo)入的excel表格伴隨著業(yè)務(wù)的區(qū)別各不相同,但是都屬于這個(gè)系統(tǒng)。
為了提高效率,沒(méi)有必要每個(gè)業(yè)務(wù)都去實(shí)現(xiàn)一套文件導(dǎo)入的邏輯,我們可以定義出一套Excel導(dǎo)入的業(yè)務(wù)邏輯模板,后續(xù)任何業(yè)務(wù)的Excel導(dǎo)入只需要繼承定義好的模板去實(shí)現(xiàn)各自的方法即可。
下面我們就根據(jù)上面描述的業(yè)務(wù)場(chǎng)景來(lái)模擬一下實(shí)現(xiàn)過(guò)程:
1.業(yè)務(wù)dto:用戶(hù)類(lèi)和商品類(lèi);
@Data public class UserImportDto {/*** 用戶(hù)名稱(chēng)*/private String name;/*** 家庭地址*/private String message;/*** 年齡*/private Integer age;} @Data public class ProductDto {/*** 商品名稱(chēng)*/private String productName;/*** 商品編碼*/private String productCode;/*** 商品使用信息*/private String productInfo;/*** 商品價(jià)格*/private BigDecimal price; }2.核心的抽象模板類(lèi):
/*** 不同業(yè)務(wù)的Excel表格導(dǎo)入公共實(shí)現(xiàn)模板;* 如果系統(tǒng)的所有excel導(dǎo)入都使用公共模板,除了業(yè)務(wù)不一樣,導(dǎo)入的過(guò)程是一樣的。*/ @Slf4j public abstract class ImportTemplate<T> {public Result importMethod(String fileName) {// 1.獲取模板文件列頭信息以及導(dǎo)入文件的列頭信息String fileHeadTemplate = fileHeadTemplate();String columnHeads = getColumnHeads(fileName);// 2.校驗(yàn)導(dǎo)入數(shù)據(jù)的列頭是否和模板匹配;Boolean checkHeads = checkFileColumnHead(fileHeadTemplate,columnHeads);if (!checkHeads) {return Result.err("導(dǎo)入文件列頭與定義的表格列頭不一致!");}// 3.若列頭符合要求,獲取表中數(shù)據(jù)List<T> dataList = getFileData(fileName);if (CollectionUtils.isEmpty(dataList)) {log.info("未獲取到業(yè)務(wù)數(shù)據(jù),導(dǎo)入失敗!");return Result.err("未獲取到導(dǎo)入的業(yè)務(wù)數(shù)據(jù)!");}// 4.導(dǎo)入的數(shù)據(jù)進(jìn)行各自的業(yè)務(wù)校驗(yàn)Boolean ok = checkDataList(dataList);if (!ok) {return Result.err("數(shù)據(jù)業(yè)務(wù)校驗(yàn)失敗!");}// 5.業(yè)務(wù)校驗(yàn)通過(guò),保存數(shù)據(jù)saveData(dataList);return Result.ok("導(dǎo)入成功!");}/*** 需要導(dǎo)入的excel表格的列頭樣式;* @return*/protected abstract String fileHeadTemplate();/*** 獲取導(dǎo)入文件的列頭;** @return*/protected abstract String getColumnHeads(String fileName);/*** 校驗(yàn)導(dǎo)入的列頭是否和模板樣例一致;** @return*/protected abstract Boolean checkFileColumnHead(String fileHeadTemplate,String columnHeads);/*** 獲取導(dǎo)入數(shù)據(jù)** @return*/protected abstract List<T> getFileData(String fileName);/*** 對(duì)導(dǎo)入的數(shù)據(jù)進(jìn)行各種業(yè)務(wù)校驗(yàn)** @param dataList* @return*/protected abstract Boolean checkDataList(List<T> dataList);/*** 校驗(yàn)后的數(shù)據(jù)導(dǎo)入到服務(wù)器或者記錄到數(shù)據(jù)庫(kù)中;* @param list*/protected abstract void saveData(List<T> list);}3.模板實(shí)現(xiàn)類(lèi):用戶(hù)Excel導(dǎo)入和商品Excel導(dǎo)入
@Slf4j public class UserInfoImport extends ImportTemplate<UserImportDto> {@Overrideprotected String fileHeadTemplate(){log.info("用戶(hù)excel表格模板==={}","用戶(hù)名稱(chēng),家庭地址,年齡");return "用戶(hù)名稱(chēng),家庭地址,年齡";}@Overrideprotected String getColumnHeads(String fileName) {// 此處省略實(shí)際獲取用戶(hù)導(dǎo)入文件列頭信息的業(yè)務(wù)邏輯,非設(shè)計(jì)模式關(guān)注的重點(diǎn);log.info("獲取用戶(hù)導(dǎo)入文件的表頭==={}","用戶(hù)名稱(chēng),家庭地址,年齡");return "用戶(hù)名稱(chēng),家庭地址,年齡";}@Overrideprotected Boolean checkFileColumnHead(String fileHeadTemplate,String columnHeads) {// 如果導(dǎo)入文件的列頭和模板定義的列頭一致,校驗(yàn)通過(guò)if(fileHeadTemplate.equals(columnHeads)){log.info("用戶(hù)excel表格導(dǎo)入文件表頭校驗(yàn)通過(guò)");return true;}return false;}@Overrideprotected List<UserImportDto> getFileData(String fileName) {// 模擬從Linux文件服務(wù)器上獲取導(dǎo)入文件的數(shù)據(jù)List<UserImportDto> list = new ArrayList<>();log.info("獲取導(dǎo)入用戶(hù)數(shù)據(jù)");// 業(yè)務(wù)代碼省略。。。return list;}@Overrideprotected Boolean checkDataList(List<UserImportDto> dataList) {// 對(duì)獲取的數(shù)據(jù)進(jìn)行業(yè)務(wù)校驗(yàn),比如姓名必須填寫(xiě);for(UserImportDto userImportDto : dataList){if(StringUtils.isEmpty(userImportDto.getName())){return false;}}log.info("導(dǎo)入的用戶(hù)數(shù)據(jù)校驗(yàn)通過(guò)");return true;}@Overrideprotected void saveData(List<UserImportDto> list) {// 模擬實(shí)際的保存用戶(hù)數(shù)據(jù)業(yè)務(wù)邏輯// 數(shù)據(jù)入庫(kù)或存儲(chǔ)文件的代碼省略...log.info("用戶(hù)數(shù)據(jù)保存成功!");} } @Slf4j public class ProductImport extends ImportTemplate<ProductDto> {@Overrideprotected String fileHeadTemplate() {log.info("商品excel表格模板==={}","用戶(hù)名稱(chēng),家庭地址,年齡");return "商品名稱(chēng),商品編碼,商品使用信息,商品價(jià)格";}@Overrideprotected String getColumnHeads(String fileName) {// 此處省略實(shí)際獲取商品導(dǎo)入文件列頭信息的業(yè)務(wù)邏輯,非設(shè)計(jì)模式關(guān)注的重點(diǎn);log.info("獲取商品導(dǎo)入文件的表頭==={}","商品名稱(chēng),商品編碼,商品使用信息,商品價(jià)格");return "商品名稱(chēng),商品編碼,商品使用信息,商品價(jià)格";}@Overrideprotected Boolean checkFileColumnHead(String fileHeadTemplate, String columnHeads) {// 如果導(dǎo)入文件的列頭和模板定義的列頭一致,校驗(yàn)通過(guò)if (fileHeadTemplate.equals(columnHeads)) {log.info("商品excel表格導(dǎo)入文件表頭校驗(yàn)通過(guò)");return true;}return false;}@Overrideprotected List<ProductDto> getFileData(String fileName) {// 模擬從專(zhuān)門(mén)的文件云服務(wù)器獲取導(dǎo)入文件的數(shù)據(jù)List<ProductDto> list = new ArrayList<>();ProductDto productDto = new ProductDto();productDto.setProductName("娃哈哈");productDto.setProductCode("123");productDto.setProductInfo("可以喝的AD鈣奶");productDto.setPrice(new BigDecimal("1"));list.add(productDto);log.info("獲取導(dǎo)入商品數(shù)據(jù)");// 業(yè)務(wù)代碼省略。。。return list;}@Overrideprotected Boolean checkDataList(List<ProductDto> dataList) {// 對(duì)獲取的數(shù)據(jù)進(jìn)行業(yè)務(wù)校驗(yàn),比如姓名必須填寫(xiě);for (ProductDto userImportDto : dataList) {if (StringUtils.isEmpty(userImportDto.getProductCode())) {return false;}}log.info("導(dǎo)入的商品數(shù)據(jù)校驗(yàn)通過(guò)");return true;}@Overrideprotected void saveData(List<ProductDto> list) {// 模擬實(shí)際的商品保存數(shù)據(jù)業(yè)務(wù)邏輯// 數(shù)據(jù)入庫(kù)或存儲(chǔ)文件的代碼省略...log.info("商品數(shù)據(jù)保存成功!");} }4.測(cè)試類(lèi):
public class TemplateModelDemo {public static void main(String[] args) {System.out.println("模擬導(dǎo)入的用戶(hù)表格中無(wú)用戶(hù)信息");ImportTemplate userInfoImport = new UserInfoImport();userInfoImport.importMethod("xxxx");System.out.println("模擬導(dǎo)入有商品表格含有商品信息");ImportTemplate productImport = new ProductImport();productImport.importMethod("xxxx");}}5.測(cè)試結(jié)果:
?三、總結(jié)
通過(guò)上面的實(shí)現(xiàn)可以看到模板方法模式在定義統(tǒng)一的結(jié)構(gòu)也就是執(zhí)行標(biāo)準(zhǔn)方面非常的方便,能很好的做到讓后續(xù)實(shí)現(xiàn)者不用關(guān)心調(diào)用邏輯,只需按照統(tǒng)一方式執(zhí)行即可。
另外,模板方法模式也是為了解決子類(lèi)通用方法,放到父類(lèi)中進(jìn)行優(yōu)化設(shè)計(jì)。讓每一個(gè)子類(lèi)只做子類(lèi)需要完成的事情,而不需要關(guān)心其它邏輯。
簡(jiǎn)單總結(jié):行為由父類(lèi)統(tǒng)一管理,可變擴(kuò)展部分由子類(lèi)各自實(shí)現(xiàn)。
總結(jié)
以上是生活随笔為你收集整理的模板方法模式介绍与示例的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 韩商言喊你来使用模切ERP系统
- 下一篇: Box2D的安装小结