重构Java方法,以使代码不会被标记为重复

问题描述

我有一个使用Spring Boot和Spring Data JPA接口的项目。有一种方法出现在5个服务中,并且我的IDE将代码标记为重复。我将发布其中的两种方法,以便您可以看到代码的外观,它们基本上是相同的,唯一不同的是所使用的存储库接口。

AccountRequestService.java 中,我有这种方法


    public Page<AccountRequest> getAccountRequestPageable(final Pageable pageable,final String status) {

        Page<AccountRequest> accountRequestPage;

        if (UNCOMPLETED_STATUS.equals(status)) {
            accountRequestPage = accountRequestRepository.findByBaseRequestinitiatorIgnoreCaseAndBaseRequestOutdatedDaysGreaterThanAndBaseRequestStatus(pageable,LoggedUserUtil.getLoggedUserName(),BaseRequestStatusType.APPROVED);
        } else {
            if (!ALL_STATUS.equals(status)) {
                accountRequestPage = accountRequestRepository.findByBaseRequestStatusAndBaseRequestinitiatorIgnoreCase(pageable,BaseRequestStatusType.valueOf(status),LoggedUserUtil.getLoggedUserName());
            } else {
                accountRequestPage = accountRequestRepository.findByBaseRequestinitiatorIgnoreCase(pageable,LoggedUserUtil.getLoggedUserName());
            }
        }
        return accountRequestPage;
    }

在ApplicationRequestService.java中:

  public Page<ApplicationsRequest> getApplicationsRequestPageable(final Pageable pageable,final String status) {
        Page<ApplicationsRequest> applicationsRequestPage;
        if (UNCOMPLETED_STATUS.equals(status)) {
            applicationsRequestPage = applicationRequestRepository
                    .findByBaseRequestinitiatorIgnoreCaseAndBaseRequestOutdatedDaysGreaterThanAndBaseRequestStatus(pageable,BaseRequestStatusType.APPROVED);
        } else {
            if (!ALL_STATUS.equals(status)) {
                applicationsRequestPage = applicationRequestRepository.findByBaseRequestStatusAndBaseRequestinitiatorIgnoreCase(
                        pageable,LoggedUserUtil.getLoggedUserName());
            } else {
                applicationsRequestPage = applicationRequestRepository.findByBaseRequestinitiatorIgnoreCase(pageable,LoggedUserUtil.getLoggedUserName());
            }
        }
        return applicationsRequestPage;
    }

我将发布 AccountRequestRepository 代码,因为 ApplicationRequestRepository 很相似,但是引用的对象类型是 ApplicationRequest ,而不是 AccountRequest :

public interface AccountRequestRepository extends JpaRepository<AccountRequest,Long> {
    AccountRequest findByBaseRequestId(Long id);

    Page<AccountRequest> findByBaseRequestinitiatorIgnoreCaseAndBaseRequestOutdatedDaysGreaterThanAndBaseRequestStatus(Pageable pageable,String initiator,Integer days,BaseRequestStatusType status);

    Page<AccountRequest> findByBaseRequestStatusAndBaseRequestinitiatorIgnoreCase(Pageable pageable,BaseRequestStatusType baseRequestStatusType,String initiator);

    Page<AccountRequest> findByBaseRequestinitiatorIgnoreCase(Pageable pageable,String loggedUserName);

}

现在,我想知道是否有任何方法可以重构此代码,以便消除重复的代码。我试图找到使用Java 8并传递函数解决方案,但我真的无法弄清楚如何对此进行参数化。

解决方法

我认为您需要创建“请求”接口并使用Hibernate的实体继承(Spring Data将理解)来获取Page 。参见https://www.baeldung.com/hibernate-inheritance

然后,您可以使用Request接口放置通用逻辑,甚至可以将Request定义为存储该通用逻辑(即调用)的超类!

,

如果您不能或者由于某种原因不想修改您现有的类结构,那么仍然可以使用一些方法来重构此类代码。例如,您可以将查询函数作为参数传递给决定要调用哪些查询的通用函数,例如

public Page<AccountRequest> getAccountRequestPageable(final Pageable pageable,final String status) {
    return getPageable(pageable,status,p -> accountRequestRepository.findByBaseRequestInitiatorIgnoreCaseAndBaseRequestOutdatedDaysGreaterThanAndBaseRequestStatus(p,LoggedUserUtil.getLoggedUserName(),BaseRequestStatusType.APPROVED),p -> accountRequestRepository.findByBaseRequestInitiatorIgnoreCase(p,LoggedUserUtil.getLoggedUserName()),p -> accountRequestRepository.findByBaseRequestStatusAndBaseRequestInitiatorIgnoreCase(p,BaseRequestStatusType.valueOf(status),LoggedUserUtil.getLoggedUserName()));
}

public Page<ApplicationsRequest> getApplicationsRequestPageable(final Pageable pageable,p -> applicationRequestRepository.findByBaseRequestInitiatorIgnoreCaseAndBaseRequestOutdatedDaysGreaterThanAndBaseRequestStatus(pageable,p -> applicationRequestRepository.findByBaseRequestInitiatorIgnoreCase(pageable,p -> applicationRequestRepository.findByBaseRequestStatusAndBaseRequestInitiatorIgnoreCase(pageable,LoggedUserUtil.getLoggedUserName()));                            
}
           
public static <T,Q> Page<Q> getPageable(final Pageable pageable,final String status,Function<Pageable,Page<Q>> findUncompleted,Page<Q>> findAll,Page<Q>> findOther
        ) {

    Page<Q> accountRequestPage;

    if (UNCOMPLETED_STATUS.equals(status)) {
        accountRequestPage = findUncompleted.apply(pageable);
    } else {
        if (!ALL_STATUS.equals(status)) {
            accountRequestPage = findOther.apply(pageable);
        } else {
            accountRequestPage = findAll.apply(pageable);
        }
    }
    return accountRequestPage;
}

这种重构是否有意义取决于项目,因此通常无法回答。在考虑代码重复时,重要的是要考虑相似性可能只是巧合的可能性。如果两个段的代码现在看起来相似,但是将来需要独立更改,最好将它们分开。如果他们确实在您的业务领域中拥有可以被抽象出来的基本原则,那就可以这样做。换句话说,遵循“单一责任原则”,即“改变的唯一原因”。