具有多个if条件的编码标准

Shi*_*rty 15 java

我需要根据某些条件在实体中设置数据.

我用下面的数据来设置

if (StringUtils.isNotBlank(customerVO.getGender())) {
    mstCustomer.setGender(customerVO.getGender());
}
if (StringUtils.isNotBlank(customerVO.getBirthDate())) {
    mstCustomer.setDob(DateUtils.getUtilDate(customerVO.getBirthDate()));
}

if (StringUtils.isNotBlank(customerVO.getAdd1())) {
    mstCustomer.setAddress1(customerVO.getAdd1());
}
if (StringUtils.isNotBlank(customerVO.getAdd2())) {
    mstCustomer.setAddress2(customerVO.getAdd2());
}
if (StringUtils.isNotBlank(customerVO.getAdd3())) {
    mstCustomer.setAddress3(customerVO.getAdd3());
}
if (StringUtils.isNotBlank(customerVO.getPincode())) {
    mstCustomer.setPinCode(customerVO.getPincode());
}
if (StringUtils.isNotBlank(customerVO.getStateName())) {
    MstState state = mstStateRepository.findByName(customerVO.getStateName());
    mstCustomer.setMstState(state);
}

if (StringUtils.isNotBlank(customerVO.getCity())) {
    MstCity city = mstCityRepository.findByName(customerVO.getCity());
    mstCustomer.setMstCity(city);
}

if (StringUtils.isNotBlank(customerVO.getIdentificationType())) {
    mstCustomer.setIdentificationType(customerVO.getIdentificationType());
}

if (StringUtils.isNotBlank(customerVO.getIdentificationData())) {
    mstCustomer.setIdentificationData(customerVO.getIdentificationData());
}

MstStatus mstStatus = mstStatusRepository.findOne(MstStatusEnum.CUST_ACTIVE.getStatusCode());
if (mstStatus != null) {
    mstCustomer.setMstStatus(mstStatus);
}

if (!StringUtils.isBlank(customerVO.getMaritalStatus())) {
    mstCustomer.setMaritalStatus(customerVO.getMaritalStatus());
}
if (StringUtils.isBlank(customerVO.getWeddingAnniversary())) {
    mstCustomer.setWeddingAnniversary(DateUtils.getDateFromString(customerVO.getWeddingAnniversary()));
}

if (StringUtils.isNotBlank(customerVO.getMotherTongue())) {
    mstCustomer.setMotherTongue(customerVO.getMotherTongue());
}
if (StringUtils.isNotBlank(customerVO.getFamilySize())) {
    mstCustomer.setFamilySize(Integer.valueOf(customerVO.getFamilySize()));
}
if (StringUtils.isNotBlank(customerVO.getAdultsSize())) {
    mstCustomer.setAdultsSize(Integer.valueOf(customerVO.getAdultsSize()));
}
if (StringUtils.isNotBlank(customerVO.getNoOfKids())) {
    mstCustomer.setNoOfKids(Integer.valueOf(customerVO.getNoOfKids()));
}
if (StringUtils.isNotBlank(customerVO.getChilddob1())) {
    mstCustomer.setChilddob1(DateUtils.getDateFromString(customerVO.getChilddob1()));
}
if (StringUtils.isNotBlank(customerVO.getChilddob2())) {
    mstCustomer.setChilddob2(DateUtils.getDateFromString(customerVO.getChilddob2()));
}
if (StringUtils.isNotBlank(customerVO.getProfession())) {
    mstCustomer.setProfession(customerVO.getProfession());
}
Run Code Online (Sandbox Code Playgroud)

但是声纳抛出这个例外: Refactor this method to reduce its Cognitive Complexity from 27 to the 15 allowed.

请建议重构上述代码的最佳方法是什么.

Dic*_*ici 19

使用lambdas似乎很可行:

private void setIfNotBlank(String value, Consumer<String> setter)  {
    setConditionally(value, setter, StringUtils::isNotBlank);
}

// if you don't need non-string arguments you can inline this method
private <T> void setConditionally(T value, Consumer<T> setter, Predicate<T> shouldSet) {
    if (shouldSet.test(value)) setter.accept(value);
}
Run Code Online (Sandbox Code Playgroud)

然后,

if (StringUtils.isNotBlank(customerVO.getBirthDate())) {
    mstCustomer.setDob(DateUtils.getUtilDate(customerVO.getBirthDate()));
}

if (StringUtils.isNotBlank(customerVO.getCity())) { 
    MstCity city = mstCityRepository.findByName(customerVO.getCity()); 
    mstCustomer.setMstCity(city); 
}
Run Code Online (Sandbox Code Playgroud)

会成为

setIfNotBlank(customerVO.getBirthDate(), birthDate -> mstCustomer.setDob(DateUtils.getUtilDate(birthDate)));
setIfNotBlank(customerVO.getCity(), cityName -> { 
    MstCity city = mstCityRepository.findByName(cityName); 
    mstCustomer.setMstCity(city); 
});
Run Code Online (Sandbox Code Playgroud)


Joh*_*ica 16

这非常适合Optional.首先,创建一个帮助方法将每个可能空白的字段转换为Optional<String>.

Optional<String> optional(String value) {
    return StringUtils.isNotBlank(value)
        ? Optional.of(value)
        : Optional.empty();
}
Run Code Online (Sandbox Code Playgroud)

然后,像这样重写代码:

optional(customerVO.getGender())   .ifPresent(mstCustomer::setGender);
optional(customerVO.getBirthDate()).map(DateUtils::getUtilDate)
                                   .ifPresent(mstCustomer::setDob);

optional(customerVO.getAdd1())     .ifPresent(mstCustomer::setAddress1);
optional(customerVO.getAdd2())     .ifPresent(mstCustomer::setAddress2);
optional(customerVO.getAdd3())     .ifPresent(mstCustomer::setAddress3);
optional(customerVO.getPincode())  .ifPresent(mstCustomer::setPinCode);
optional(customerVO.getStateName()).map(mstStateRepository::findByName)
                                   .ifPresent(mstCustomer::setMstState);

optional(customerVO.getCity())     .map(mstCityRepository::findByName)
                                   .ifPresent(mstCustomer::setMstCity);

optional(customerVO.getIdentificationType()).ifPresent(mstCustomer::setIdentificationType);
optional(customerVO.getIdentificationData()).ifPresent(mstCustomer::setIdentificationData);

Optional.of(MstStatusEnum.CUST_ACTIVE.getStatusCode())
    .map(mstStatusRepository::findOne)
    .ifPresent(mstCustomer::setMstStatus);

optional(customerVO.getMaritalStatus())     .ifPresent(mstCustomer::setMaritalStatus);
optional(customerVO.getWeddingAnniversary()).map(DateUtils::getDateFromString)
                                            .ifPresent(mstCustomer::setWeddingAnniversary);

optional(customerVO.getMotherTongue()).ifPresent(mstCustomer::setMotherTongue);
optional(customerVO.getFamilySize())  .map(Integer::valueOf).ifPresent(mstCustomer::setFamilySize);
optional(customerVO.getAdultsSize())  .map(Integer::valueOf).ifPresent(mstCustomer::setAdultsSize);
optional(customerVO.getNoOfKids())    .map(Integer::valueOf).ifPresent(mstCustomer::setNoOfKids);
optional(customerVO.getChilddob1())   .map(DateUtils::getDateFromString).ifPresent(mstCustomer::setChilddob1);
optional(customerVO.getChilddob2())   .map(DateUtils::getDateFromString).ifPresent(mstCustomer::setChilddob2);
optional(customerVO.getProfession())  .ifPresent(mstCustomer::setProfession);
Run Code Online (Sandbox Code Playgroud)

ifPresent仅当字段为非空时才调用命名函数.map有助于将值从一种类型转换为另一种类型.请注意这有助于使逻辑变平,以便映射与设置分离.


Jok*_*_vD 7

在我看来,这段代码从根本上无法改进.就其本质而言,它是乏味和重复的.它将一个对象的属性转换为另一个对象的属性,而Java根本不提供简短明了的表达方式.

考虑其他答案:他们将原始代码的单个if语句转换为另一个语句,而不是20 if秒,最终会有20 个optional()调用或20个setIfNotBlank()调用 - 但代码的主要问题是有20个长,类似在一个方法中,你仍然以20个长而相似的陈述结束,因此它们没有太大的改进.

您可以转向反射:发明一些注释并用它们注释类customerVOmstCustomer对象,然后在"对于第一个对象上的每个注释,在第二个对象上找到相应的注释,执行赋值"的静脉中重写此方法. .但现在有20个长长的,相似的if陈述,你有40个长而相似的注释,而且它们分为两个不同的文件.更糟糕的是,如果你选择这样做,试着只注释其中一个类而不是两个类:那么你最终只会有20个注释,所以事情就像以前一样糟糕.

您可以转向代码生成:发明一些简单的属性描述格式(或找到现有的格式),编写一个小工具来获取此描述并生成类customerVOmstCustomer对象的代码.现在,不再是20个长期,类似的if陈述,你有20个希望简短,可能不是那么相似的属性描述,只有你知道的语言和构建链中的其他工具.

正如你所看到的,你无法逃避写出20个长期无聊的相似外观.

所以我的答案是:不要重构它.将此代码customerVO以及mstCustomer对象的类标记为已连接,并确保始终同步更改它们.这并不意味着为它编写一些单元测试 - 虽然你也应该这样做 - 这意味着建立一个程序.这不再是技术问题:这是一个人的问题.告诉其他开发人员这段代码; 在此代码中写下评论"别忘了检查其他部分"; 使用代码中这些部分的更改来检查提交.您不能依靠自动化工具来保持此代码的正确性,因此您和您的同事必须记住手动执行此操作.


Axe*_*l M 5

解决这个问题的最简单方法,可以通过为所有这些任务编写setter来实现.

喜欢:

private void setGender(GenderObject customerVO){
    if (StringUtils.isNotBlank(customerVO.getGender())) {
        this.setGender(customerVO.getGender());
    }
}
Run Code Online (Sandbox Code Playgroud)