Хороший дизайн для отображения объектов if else

#java #if-statement #conditional-statements

#java #if-оператор #условные операторы

Вопрос:

У меня есть такая логика:

 public void method(Boo result, Foo foo, Bar bar) {
   if(foo != null) {
      if(foo.getId() != null){
         result.setId(foo.getId());
      } else {
         result.setId(bar.getId());
      }
      if(foo.getName() != null){
         boo.setName(foo.getName());
      } else {
         result.setName(bar.getName());
      }
      // and many similar attributes
   } else {
      result.setId(bar.getId());
      result.setName(bar.getName());
      // and many similar attributes
   }
}
  

Я нахожу этот способ уродливым, есть ли какой-нибудь способ улучшить его дизайн. Я знаю, что лучше использовать mapstruct, но в этом проекте я не могу.

Комментарии:

1. Использование троичного оператора превратило бы каждое if / else в одну строку. Однако, является ли это менее уродливым / более читаемым / лучшим для ваших целей, это совершенно другой вопрос.

2. @JustAnotherDeveloper У меня длинные атрибуты, если я использую тернарный оператор, это тоже может быть некрасиво

3. Если вы можете изменить объекты, возвращающие все эти поля с нулевым значением, вы могли бы использовать Optional . Однако это не очень поможет, если вы только обернете вещи локально здесь, в вашем method .

4. Если вы используете kotlin , вы можете использовать безопасные вызовы с операторами elvis , и проверки могут быть упрощены до одной строки.

5. @Marc Пожалуйста, прочтите руководство по проверке кода для пользователей Stack Overflow и обратите внимание, что текущий код не будет принят в Code Review за то, что он гипотетический.

Ответ №1:

Я бы поменял тесты. Это немного чище, но все равно будет выглядеть неаккуратно.

 public void method(Boo result, Foo foo, Bar bar) {
    setResult(result, bar);
    if (foo != null) { setResult(result, foo); }
}

private void setResult(Boo result, Bar bar) {
    result.setId(bar.getId());
    ...
}

private void setResult(Boo result, Foo foo) {
    if (foo.getId != null) { result.setId(foo.getId()); }
    ...
} 
  

Комментарии:

1. Я согласен с последним предложением , но это все равно будет выглядеть неаккуратно 🙂

Ответ №2:

С общим классом / интерфейсом:

Если Foo и Bar расширить общий базовый класс / интерфейс, вы могли бы создать универсальный метод для применения логики к любому атрибуту.

Например, допустим, что они реализуют этот интерфейс:

 public interface IBaseInterface {
    Long getId();
    String getName();
}
  

Тогда мы могли бы создать этот универсальный метод:

 public static <T> T getAttribute(IBaseInterface foo, IBaseInterface bar, Function<IBaseInterface, T> function) {
    if(foo != null) {
        T attribute = function.apply(foo);
        if(attribute != null) {
            return attribute;
        }
    }
    return function.apply(bar);
}
  

И используйте его следующим образом:

 result.setId(getAttribute(foo, bar, IBaseInterface::getId));
result.setName(getAttribute(foo, bar, IBaseInterface::getName));
  

Без общего класса / интерфейса:

Если они не расширяют общий базовый класс / интерфейс, вы все равно можете использовать этот метод, но вам придется передать методу другой параметр:

 public static <T> T getAttribute(Foo foo, Bar bar, Function<Foo, T> functionFoo, Function<Bar, T> functionBar) {
    if(foo != null) {
        T attribute = functionFoo.apply(foo);
        if(attribute != null) {
            return attribute;
        }
    }
    return functionBar.apply(bar);
}
  

И используйте его следующим образом:

 result.setId(getAttribute(foo, bar, Foo::getId, Bar::getId));
result.setName(getAttribute(foo, bar, Foo::getName, Bar::getName));
  

Комментарии:

1. Оба ответа очень хороши, спасибо за ваш ответ, я немного подожду, если нет лучшего решения, я приму один из них

Ответ №3:

Я избегаю использования if else ObjectUtils::firstNonNull как показано ниже:

 public void method(Boo result, Foo foo, Bar bar) {
   if(foo != null) {
      result.setId(ObjectUtils.firstNonNull(foo.getId(), bar.getId()));
      result.setId(ObjectUtils.firstNonNull(foo.getName(), bar.getName()));
      // and many similar attributes
   } else {
      result.setId(bar.getId());
      result.setName(bar.getName());
      // and many similar attributes
   }
}
  

Я открыт для других предложений!

Ответ №4:

Имея foo в Optional качестве, вы могли бы упростить свой код следующим образом:

 Optional<Foo> optionalFoo = Optional.ofNullable(foo);
    
result.setId(optionalFoo.map(Foo::getId).orElseGet(bar::getId));
result.setName(optionalFoo.map(Foo::getName).orElseGet(bar::getName));
// ...
  

Ответ №5:

if операторам не нужны фигурные скобки {} , когда после этого есть один оператор. Думайте об этом как {...} об одном операторе, заключающем в себе множество других.
Также Java на самом деле не заботится о пробелах и отступах, поэтому вы можете поместить несколько операторов в одну строку.

С этими знаниями вы можете сделать код красивее, например, так:

 public void method(Boo result, Foo foo, Bar bar) {
    if (foo != null) {
        if (foo.getId() != null) result.setId(foo.getId());
        else result.setId(bar.getId());

        if (foo.getName() != null) boo.setName(foo.getName());
        else result.setName(bar.getName());

    } else {
        result.setId(bar.getId());
        result.setName(bar.getName());
   }
}
  

или, по крайней мере, удалите {} :

 public void method(Boo result, Foo foo, Bar bar) {
    if (foo != null) {
        if (foo.getId() != null)
            result.setId(foo.getId());
        else 
            result.setId(bar.getId());

        if (foo.getName() != null)
            boo.setName(foo.getName());
        else 
            esult.setName(bar.getName());

    } else {
        result.setId(bar.getId());
        result.setName(bar.getName());
   }
}
  

Комментарии:

1. Проблема не в длинном или коротком

Ответ №6:

Если объекты сопоставления имеют одинаковые свойства, и если у вас есть spring beans в зависимости от вашего проекта, BeanUtils.copyProperties (источник, назначение);