一. 背景
- 最近在降低代码重复度的时候,发现有很多方法的整体流程相同,只是中间某些环节的细节不同。为了降低代码重复度,第一次知道函数式接口可以这样用,写出来看着还是很高级的,下面记录一下。
二. 正常写法
- 可以看到,
TestApiImpl
中三个方法都用了try…catch…的写法,整体流程类似,只是处理方式不同,看起来代码很冗余。
public interface TestApi {
ResultModel<ATestDTO> test1(String param1, String param2);
ResultModel<BTestDTO> test2(String param1, String param2, String param3);
ResultModel<CTestDTO> test3(String param);
}
public class TestApiImpl implements TestApi {
@Autowired
private TemplateTestManager templateTestManager;
private static final String TEST_FLAG = "TEST_FLAG";
@Override
public ResultModel<ATestDTO> test1(String param1, String param2) {
try{
return new ResultModel<>(templateTestManager.test1(param1, param2));
}catch (BizException biz){
LogBusUtil.error(TEST_FLAG, biz.getMessage(), "param1={}, param2={}", param1, param2);
return new ResultModel<>(biz.getCode(), biz.getMessage());
}catch (Exception e){
LogBusUtil.error(TEST_FLAG, "TEST1()异常", e, "param1={}, param2={}", param1, param2);
return new ResultModel<>(ServiceEnum.SYSTEM_ERROR.getCode(), ServiceEnum.SYSTEM_ERROR.getValue());
}
}
@Override
public ResultModel<BTestDTO> test2(String param1, String param2, String param3) {
try{
return new ResultModel<>(templateTestManager.test2(param1, param2, param3));
}catch (BizException biz){
LogBusUtil.error(TEST_FLAG, biz.getMessage(), "param1={}, param2={}, param3={}", param1, param2, param3);
return new ResultModel<>(biz.getCode(), biz.getMessage());
}catch (Exception e){
LogBusUtil.error(TEST_FLAG, "TEST2()异常", e, "param1={}, param2={}, param3={}", param1, param2, param3);
return new ResultModel<>(ServiceEnum.SYSTEM_ERROR.getCode(), ServiceEnum.SYSTEM_ERROR.getValue());
}
}
@Override
public ResultModel<CTestDTO> test3(String param) {
try{
return new ResultModel<>(templateTestManager.test3(param));
}catch (BizException biz){
LogBusUtil.error(TEST_FLAG, biz.getMessage(), "param1={}", param1);
return new ResultModel<>(biz.getCode(), biz.getMessage());
}catch (Exception e){
LogBusUtil.error(TEST_FLAG, "TEST3()异常", e, "param1={}", param1);
return new ResultModel<>(ServiceEnum.SYSTEM_ERROR.getCode(), ServiceEnum.SYSTEM_ERROR.getValue());
}
}
}
三. 使用函数式接口改良
- 增加两个类:
ExecuteTemplate
和ResultModelHelper
@FunctionalInterface
public interface ExecuteTemplate<T> {
T execute();
}
public class ResultModelHelper<T> {
private static final String TEST_FLAG = "TEST_FLAG";
public ResultModel<T> queryResult(ExecuteTemplate<T> template, String logDesc, String... param) {
try {
return new ResultModel<T>(template.execute());
} catch (BizException biz) {
LogBusUtil.error(TEST_FLAG, logDesc+":"+ biz.getMessage(), "param = {}", JSON.toJSONString(param));
return new ResultModel<T>(biz.getCode(), biz.getMessage());
} catch (Exception e) {
LogBusUtil.error(TEST_FLAG, logDesc, e, "param = {}", JSON.toJSONString(param));
return new ResultModel<T>(ServiceEnum.SYSTEM_ERROR.getCode(), ServiceEnum.SYSTEM_ERROR.getValue());
}
}
}
- 这样,重写一次
TestApiImpl
,如下代码,看起来简洁明了,重复度降低了很多。
public class TestApiImplNew implements TestApi {
@Autowired
private TemplateTestManager templateTestManager;
@Override
public ResultModel<ATestDTO> test1(String param1, String param2) {
return new ResultModelHelper<ATestDTO>().queryResult(() -> templateTestManager.test1(param1, param2), "TEST1()", param1, param2);
}
@Override
public ResultModel<BTestDTO> test2(String param1, String param2, String param3) {
return new ResultModelHelper<BTestDTO>().queryResult(() -> templateTestManager.test2(param1, param2, param3), "TEST2()", param1, param2, param3);
}
@Override
public ResultModel<CTestDTO> test3(String param) {
return new ResultModelHelper<CTestDTO>().queryResult(() -> templateTestManager.test3(param), "TEST3()", param);
}
}