代码重构记录

旧代码复用率低,导致重复代码多,耦合严重,往往修改一个参数就需要修改多个接口,一番挣扎之后决定对旧的代码进行重构

先贴出一段旧代码,因为之前忘了在本地编辑器截图,还好在git上能查看历史代码
一次代码重构记录 - 图1

可以看到框住的这一部分代码,都是一些对参数的校验代码或者是业务的校验代码,这部分的代码不适合放在具体的业务实现类中,这会导致这个方法”责任”过重,也违反了单一职责,针对这一部分的代码,使用了AOP进行处理,将校验(验证)的代码都放在了切面中,解耦的同时也能够更加灵活地进行控制。

  1. // 定义了一个Aspect去实现
  2. public class DataValidateAspect extends Result {
  3. @Pointcut(value = "execution(...)")
  4. public void validatePointCut() {
  5. }
  6. @Around("validatePointCut()")
  7. public Object validateBeforeCheck(ProceedingJoinPoint joinPoint) throws Throwable {
  8. MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
  9. String[] paramsName = methodSignature.getParameterNames();
  10. // 获取参数下标
  11. int request = ArrayUtils.indexOf(paramsName, "xxx");
  12. int check = ArrayUtils.indexOf(paramsName, "xxx");
  13. Object[] args = joinPoint.getArgs();
  14. if (args[request] instanceof UserRequest) {
  15. ... // 忽略一些代码
  16. // 进行一系列的校验
  17. if (phoneNumber != null) {
  18. phoneNumber = filterPhone(phoneNumber);
  19. userRequest.setPhoneNumber(phoneNumber);
  20. // 校验手机号
  21. if (phoneNumber == null) {
  22. log.info("phoneNumber verification failed...");
  23. return result(StatusCode.PARAM_WRONG);
  24. }
  25. }
  26. // 校验身份证
  27. if (!checkIdCard(idCardNo)) {
  28. log.info("idCard verification failed...");
  29. return result(StatusCode.PARAM_WRONG);
  30. }
  31. userName = checkName(userName);
  32. // 校验姓名
  33. if (userName == null) {
  34. log.info("username verification failed...");
  35. return result(StatusCode.PARAM_WRONG);
  36. }
  37. ... // 忽略后续的校验代码
  38. }
  39. return joinPoint.proceed(); //
  40. }
  41. }

以上就完成了将校验从业务代码中解耦出来,并且改切面还可以配置不同的切点,对不同的实现业务进行校验的步骤。修改校验规则的时候,也只需要对切面的代码进行更改就可以影响到多个实现类。

继续贴出后面的一段代码:

一次代码重构记录 - 图2

对外暴露多个接口(Controller),但多个接口都调用了同一个Service,通过code不同去实现逻辑,如上图所示,switch…case -> todo 的方式,这样当接口数目增多,分支多了之后,一个方法的代码就是几百行,显然很不合理。因为前面的校验代码已经交给AOP去处理了,后面的逻辑代码可以进一步拆分为多个实现类去完成,这里又因为每个实现有相似的规则,于是想到了使用模板方法(设计模式)去重构。

  1. @Slf4j
  2. public abstract class AbstractCheckData extends Result {
  3. @Autowired
  4. protected BusinessMapper businessMapper;
  5. @Autowired
  6. protected UserListService userListService;
  7. @Autowired
  8. protected RequestDataMapper requestDataMapper;
  9. @Autowired
  10. protected TransHistoryService transHistoryService;
  11. /**
  12. * 实现模板(Template method)
  13. *
  14. * @param userRequest
  15. * @param checkType
  16. * @return
  17. */
  18. public final String checkData(UserRequest userRequest, String checkType) {
  19. // 1. 查询历史记录实体封装
  20. RequestDataHistory requestDataHistory = createDataHistory(userRequest, checkType);
  21. // 2. 商户信息查询
  22. Business business = getBusiness(userRequest, checkType);
  23. // 3. 用户信息查询
  24. UserList userList = getUserList(userRequest);
  25. // 4. 各项的todo
  26. return check(userRequest, requestDataHistory, business, userList);
  27. }
  28. ...
  29. /**
  30. * 交给子类实现的具体方法
  31. *
  32. * @return
  33. */
  34. protected abstract String check(UserRequest userRequest, RequestDataHistory requestDataHistory, Business findBusiness, UserList userList);
  35. }
  36. // 子类
  37. @Service
  38. public class CheckMultiImpl extends AbstractCheckData {
  39. @Override
  40. protected String check(UserRequest userRequest, RequestDataHistory requestDataHistory, Business findBusiness, UserList userList) {
  41. ... // 具体逻辑实现
  42. }
  43. }
  44. ...
  1. // 接口
  2. public interface CheckDataService {
  3. /**
  4. * 相关信息查询,根据 checkType 判断
  5. *
  6. * @param userRequest
  7. * @param checkType
  8. * @return
  9. */
  10. String checkData(UserRequest userRequest, String checkType);
  11. }
  12. @Service
  13. public class CheckDataServiceImpl<R> implements CheckDataService {
  14. @Override
  15. public String checkData(UserRequest userRequest, String checkType) {
  16. // 表驱动代替if + 多态实现
  17. Map<String, AbstractCheckData> checkDataMap = getCheckMap();
  18. AbstractCheckData checkSub = checkDataMap.get(checkType);
  19. return checkSub.checkData(userRequest, checkType);
  20. }
  21. /**
  22. * 映射表
  23. * checkType -> impl
  24. *
  25. * @return
  26. */
  27. private Map<String, AbstractCheckData> getCheckMap() {
  28. Map<String, AbstractCheckData> map = new HashMap<>();
  29. map.put("1001", checkMulti);
  30. map.put("1002", checkBlack);
  31. map.put("1003", checkGray);
  32. map.put("1004", checkActivity);
  33. map.put("1005", checkRepaymentTime);
  34. map.put("1006", checkRepaymentAmount);
  35. map.put("1007", checkRepaymentIntensity);
  36. return map;
  37. }
  38. }

重构之后,使用了模板方法模式,让步骤成为一个模板,定义一个抽象的父类,将公共的模板方法在父类中进行实现,代码清爽了不少,也更容易拓展,修改,可读性也提高了。缺点是类文件会增加(一个接口独立一个实现类)。