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

时间:2017-12-24 14:49:54

标签: 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());
}

但声纳抛出此异常:Refactor this method to reduce its Cognitive Complexity from 27 to the 15 allowed.

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

5 个答案:

答案 0 :(得分: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);
}

然后,

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); 
}

会变成

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

答案 1 :(得分:16)

这对Optional来说非常完美。首先,创建一个帮助方法,将每个可能空白的字段转换为Optional<String>

Optional<String> optional(String value) {
    return StringUtils.isNotBlank(value)
        ? Optional.of(value)
        : Optional.empty();
}

然后,像这样重写代码:

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);
仅当字段为非空时,

ifPresent才会调用命名函数。 map有助于将值从一种类型转换为另一种类型。请注意这有助于使逻辑变平,以便映射与设置分开。

答案 2 :(得分:7)

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

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

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

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

正如你所看到的,你无法逃避写出20个长期无聊的类似事物。

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

答案 3 :(得分:5)

解决此问题的最简单方法,可以通过为所有这些作业编写setter来实现。

喜欢:

@Html.ActionLink("Edit", "TipeService", "Edit",new { @onclick="getTipo(this)", @class = "btn btn-success" })

   function getTipo(actionLink) {
       var val = $("#newTipe").val();
       $(actionLink).attr('href', $(actionLink).attr('href') + '?tipe=' + val);
   }

答案 4 :(得分:2)

如果你可以用任何一种方式调用setter,你可以通过将null处理分解为可重用的转换方法来简化代码:

mstCustomer.setGender(parseString(customerVO.getGender());
mstCustomer.setDob(parseDate(customerVO.getDob());
...

,其中

String parseString(String s) {
    return StringUtils.isBlank(s) ? null : s;
}

等等。

无论您选择什么方法,消除冗余条件对于可维护性和正确性都是有利的。

我的意思是,我需要的所有证据都在你现有的代码中:

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());
}

查看不一致的条件?第一个和最后一个案例是有道理的,但只有结婚纪念日指定时才设置结婚纪念日!

通过复制粘贴和混合空处理逻辑的两个不同变体,引入了一个错误,并且,因为没有人足够耐心地真正阅读这么多重复,所以从未注意到。

总之,不要重复代码。甚至对于像空处理这样看似微不足道的东西也没有。