模版模式-最佳实践
目标
- 为什么要运用模版模式
- 模版模式带来哪些能力
- 模版模式代码
模版模式的定义
相关概念烂大街了,直接上干货,有对相关概念不明白的去百度即可
问题
如何解决几个兄弟类之间代码重复并且重复的代码当中有些行为是自身所独有的
解决方案
- 提取父类,将重复代码提取到父类
- 将重复代码差异的行为,提取抽象方法,由子类实现
- 子类实现抽象方法
代码部分
FileParser 解析行为
public interface FileParser {
String[] getSupportedFileExtensions();
boolean canParseExtension(String fileExtension);
BaseParserConfig getDefaultParserConfig();
List<RowDefinition> parse(InputStream is, BaseParserConfig parserConfig) throws Exception;
}
AbstractFileParser 提供默认实现,将重复代码提取到此类,load() 为抽象方法
public abstract class AbstractFileParser implements FileParser {
@Override
public boolean canParseExtension(String fileExtension) {
if (StringUtils.isEmpty(fileExtension)) {
return false;
}
String[] extensions = getSupportedFileExtensions();
for (String extension : extensions) {
if (extension.equalsIgnoreCase(fileExtension)) {
return true;
}
}
return false;
}
@Override
public final List<RowDefinition> parse(InputStream is, BaseParserConfig parserConfig) throws Exception {
return doParse(is, parserConfig);
}
private List<RowDefinition> doParse(InputStream is, BaseParserConfig parserConfig) throws Exception {
List<BaseRowResultSet> rowResultSets = load(is, parserConfig);
if (CollectionUtils.isEmpty(rowResultSets)) {
return new ArrayList<>(1);
}
List<BaseRowResultSet> subRowResultSets = subList(rowResultSets, parserConfig);
List<RowDefinition> rowDefinitions = new ArrayList<>(subRowResultSets.size());
for (BaseRowResultSet rowResultSet : subRowResultSets) {
boolean isFilterRow = isFilterRow(rowResultSet, parserConfig.getCellMappings());
if (!isFilterRow) {
continue;
}
rowDefinitions.add(mapRowDefinition(rowResultSet, parserConfig.getCellMappings()));
}
return rowDefinitions;
}
/**
* 加载具体资源
*
* @param is 资源
* @param parserConfig 解析配置
* @return 解析结果
* @throws Exception 如果解析异常,则抛出异常
*/
protected abstract List<BaseRowResultSet> load(InputStream is, BaseParserConfig parserConfig) throws Exception;
private List<BaseRowResultSet> subList(List<BaseRowResultSet> rowResultSets, BaseParserConfig parserConfig) {
int rowSize = rowResultSets.size();
Range<Integer> rowRange = parserConfig.getRowRange();
int titleRowIndex = parserConfig.getTitleRowIndex();
int startRowIndex = titleRowIndex == 0 ? rowRange.getStart() - 1 : rowRange.getStart() - titleRowIndex;
int endRowIndex = titleRowIndex == 0 ? rowRange.getEnd() - 1 : rowRange.getEnd() - titleRowIndex;
if (rowSize < startRowIndex || rowSize < endRowIndex) {
return rowResultSets;
}
return rowResultSets.subList(startRowIndex, endRowIndex + 1);
}
private RowDefinition mapRowDefinition(BaseRowResultSet rowResultSet, List<CellMapping> cellMappings) {
RowDefinition rowDefinition = new RowDefinition(rowResultSet.getRowIndex());
if (CollectionUtils.isEmpty(cellMappings)) {
for (int i = 0; i < rowResultSet.getCellSize(); i++) {
rowDefinition.addCellDefinition(i, rowResultSet.getString(i));
}
} else {
int cellIndex = 0;
for (CellMapping cellMapping : cellMappings) {
String fieldValue = rowResultSet.getString(cellMapping.getCellNum());
rowDefinition.addCellDefinition(cellIndex, cellMapping.convert(fieldValue));
cellIndex++;
}
}
return rowDefinition;
}
private boolean isFilterRow(BaseRowResultSet rowResultSet, List<CellMapping> cellMappings) {
if (CollectionUtils.isEmpty(cellMappings)) {
return true;
}
boolean isFilterRow = true;
for (CellMapping cellMapping : cellMappings) {
String fieldValue = rowResultSet.getString(cellMapping.getCellNum());
if (!cellMapping.filter(fieldValue)) {
isFilterRow = false;
break;
}
}
return isFilterRow;
}
}
CsvFileParser 具体解析类,完成对 csv 的解析行为
public class CsvFileParser extends AbstractFileParser {
@Override
public String[] getSupportedFileExtensions() {
return new String[]{"csv"};
}
@Override
public BaseParserConfig getDefaultParserConfig() {
return new CsvParserConfig();
}
@Override
protected List<BaseRowResultSet> load(InputStream is, BaseParserConfig parserConfig) throws Exception {
return readCsv(is);
}
protected List<BaseRowResultSet> readCsv(InputStream is) throws Exception {
return CSVUtils.read(is, new CSVRowMapper<BaseRowResultSet>() {
@Override
public BaseRowResultSet mapRow(CSVResultSet rs, int rowNum) {
return new ArrayRowResultSet(rowNum, rs.getValues());
}
});
}
}
ExcelFileParser 具体解析类,完成对 excel 的解析行为
public class ExcelFileParser extends AbstractFileParser {
@Override
public String[] getSupportedFileExtensions() {
return new String[]{"xls", "xlsx"};
}
@Override
public BaseParserConfig getDefaultParserConfig() {
return new ExcelParserConfig();
}
@Override
protected List<BaseRowResultSet> load(InputStream is, BaseParserConfig parserConfig) {
ExcelParserConfig excelParserConfig = (ExcelParserConfig) parserConfig;
List<Map<Integer, String>> mapList = readExcel(is, excelParserConfig);
return toRowResultSet(mapList);
}
private List<BaseRowResultSet> toRowResultSet(List<Map<Integer, String>> mapList) {
List<BaseRowResultSet> rowResultSets = new ArrayList<>(mapList.size());
int index = 0;
for (Map<Integer, String> map : mapList) {
rowResultSets.add(new MapRowResultSet(index, map));
index++;
}
return rowResultSets;
}
protected List<Map<Integer, String>> readExcel(InputStream is, ExcelParserConfig excelParserConfig) {
return EasyExcel.read(is)
.sheet(excelParserConfig.getSheetIndex(), excelParserConfig.getSheetName())
.headRowNumber(excelParserConfig.getRowRange().getStart())
.doReadSync();
}
}
优点
- 满足开闭原则,实现新的解析器扩展
AbstractFileParser即可
- 满足可扩展、可复用性
- 整体类层次结构比较优雅,满足易读性、可维护性
项目地址
\