日常编程中,如果使用Idea时总会遇到破浪线的代码块,鼠标悬浮上去,提示
Found Duplicated Code in XXX
。从代码设计的角度来讲,不符合DRY(Don't Repeat Yourself)
原则。那我们又如何改善你眼前看到的一切呢?对于大多数同学来讲,肯定视而不见;但对于那么一丢丢同学来讲,却无法接受这样的代码,总想重构一下。
/**
* 分页查出当前资金方绑定产品列表
* @param form
* @return
*/
@LogMonitor("资金方管理")
public Result<PageVO<ProductVo>> loadBindRecords(PageForm<FundProductForm> form) {
List<ProductVo> productVos = Collections.emptyList();
int count = 0;
try {
List<Product> products = fundProductService.selectBindProductByParams(form);
if (CollectionUtils.isEmpty(products)) {
return Result.failInEmptyRecord(null);
}
Map<String, String> productTypeMap = diamondConfigProxy.queryProductType().stream().collect(Collectors.toMap(ProductTypeRe::getCode, ProductTypeRe::getName));
productVos = new ProductVoConvertor().convertList(products, productTypeMap);
count = fundProductService.getBindProductCount(form);
}catch (Exception e){
LOGGER.error("{}loadBindRecords加载数据异常,form={}",LOG_TITLE, JSON.toJSON(form),e);
return Result.fail(PageVO.newInstance(count,productVos));
}
return Result.suc(PageVO.newInstance(count,productVos));
}
/**
* 分页查出当前资金方尚未绑定产品列表
* @param form
* @return
*/
@LogMonitor("资金方管理")
public Result<PageVO<ProductVo>> loadNotBindRecords(PageForm<FundProductForm> form) {
List<ProductVo> productVos = Collections.emptyList();
int count = 0;
try {
List<Product> products = fundProductService.selectNotBindProductByParams(form);
if (CollectionUtils.isEmpty(products)) {
return Result.failInEmptyRecord(null);
}
Map<String, String> productTypeMap = diamondConfigProxy.queryProductType().stream().collect(Collectors.toMap(ProductTypeRe::getCode, ProductTypeRe::getName));
productVos = new ProductVoConvertor().convertList(products, productTypeMap);
count = fundProductService.getNotBindProductCount(form);
}catch (Exception e){
LOGGER.error("{}loadNotBindRecords加载数据异常,form={}",LOG_TITLE, JSON.toJSON(form),e);
return Result.fail(PageVO.newInstance(count,productVos));
}
return Result.suc(PageVO.newInstance(count,productVos));
}
上面就是个方法,发现方法体中大部分代码几乎一样的,鼠标悬浮上去提示如下:
我们分析上述两个方法,得知什么结论呢?
- 1、方法入参一致。
- 2、方法返回参数一致。
- 3、方法体处理逻辑几乎一致,唯一区别就是调用 fundProductService.selectXXX 这句代码。
该函数是jdk8新出来的,用于实现函数式编程。如果它没有出现,传统逻辑,我们就需要自己定义一个接口,调用时,并实现这个接口。它的出现,则无需我们重复定义。
/**
* Represents a function that accepts one argument and produces a result.
*
* This is a functional interface
* whose functional method is {@link #apply(Object)}.
*
* @param the type of the input to the function
* @param the type of the result of the function
*
* @since 1.8
*/
@FunctionalInterface
public interface Function<T, R> {
/**
* Applies this function to the given argument.
*
* @param t the function argument
* @return the function result
*/
R apply(T t);
// 省略其他代码
}
看到上述代码,我们会发现内置了一个R apply(T t)
,什么意思呢?
Applies this function to the given argument.
(给定参数T 调用该函数返回R)
既然Function
可以允许我们自定一个函数,通过给定参数T
返回结果R
那么,对应案例中,就是给定参数PageForm
,返回结果Result
。我们顺着这个思路,把上述代码,差异的部分提取一个函数,代码如下:
public Result<PageVO<ProductVo>> loadRecords(PageForm<FundProductForm> form, Function<PageForm<FundProductForm>,List<Product>> query) {
List<ProductVo> productVos = Collections.emptyList();
int count = 0;
try {
List<Product> products = query.apply(form);
if (CollectionUtils.isEmpty(products)) {
return Result.failInEmptyRecord(null);
}
Map<String, String> productTypeMap = diamondConfigProxy.queryProductType().stream().collect(Collectors.toMap(ProductTypeRe::getCode, ProductTypeRe::getName));
productVos = new ProductVoConvertor().convertList(products, productTypeMap);
count = fundProductService.getNotBindProductCount(form);
}catch (Exception e){
LOGGER.error("{}loadNotBindRecords加载数据异常,form={}",LOG_TITLE, JSON.toJSON(form),e);
return Result.fail(PageVO.newInstance(count,productVos));
}
return Result.suc(PageVO.newInstance(count,productVos));
}
那么原先调用的方法,则修改如下:
/**
* 分页查出当前资金方绑定产品列表
* @param form
* @return
*/
@LogMonitor("资金方管理")
public Result<PageVO<ProductVo>> loadBindRecords(PageForm<FundProductForm> form) {
return loadRecords(form, arg -> fundProductService.selectBindProductByParams(form));
}
/**
* 分页查出当前资金方尚未绑定产品列表
* @param form
* @return
*/
@LogMonitor("资金方管理")
public Result<PageVO<ProductVo>> loadNotBindRecords(PageForm<FundProductForm> form) {
return loadRecords(form, arg -> fundProductService.selectNotBindProductByParams(form));
}
是不是很简单,代码瞬间看起来清新了许多。
Function
函数通畅用于封装一个通用的函数,对于参数传入的参数T
,返回结果R
。对于日常中如果代码中只是调用一个函数的差异,比如查询数据库结果集是调用不同的接口,则可以通过它来实现封装。