Как создать общий метод с оператором switch для разных типов ввода - PullRequest
1 голос
/ 27 марта 2019

Я пытаюсь реорганизовать свой код, потому что методы, которые я создал, очень похожи.Даже intelliJ подчеркивает это.Целью методов является сопоставление (с помощью операторов switch) типа «MessageType» и «MessageType» из другого пакета.Проблема заключается в том, что типы ввода для оператора switch также относятся к разным пакетам.

private MessageType convertToInsurancePolisyMessageType1 (pl.different.MessageType messageType) {
    switch (messageType) {
        case WARN: return MessageType.WARN;
        case INFO: return MessageType.INFO;
        case ERROR: return MessageType.ERROR;
        default: throw new IllegalArgumentException(messageType.name());
    }
}

private MessageType convertToInsurancePolisyMessageType2 (com.other.MessageType messageType) {
    switch (messageType) {
        case WARNING: return MessageType.WARN;
        case INFO: return MessageType.INFO;
        case ERROR: return MessageType.ERROR;
        default: throw new IllegalArgumentException(messageType.name());
    }
}

Есть ли простой способ реорганизовать это?Или я должен уйти, как это?

Ответы [ 3 ]

1 голос
/ 27 марта 2019

Ну, в конце концов, я не вижу ничего плохого в вашем подходе к переключению:)

Просто, чтобы бросить какую-то альтернативу, вы можете использовать карты:

public class MessageTypeConverter {
    private static final Map<pl.different.MessageType, com.other.MessageType> DIRECT_MAPPING = 
        new EnumMap<pl.different.MessageType, com.other.MessageType>(pl.different.MessageType.class) {{
            put(pl.different.MessageType.WARN, com.other.MessageType.WARN);
            put(pl.different.MessageType.INFO, com.other.MessageType.INFO);
            put(pl.different.MessageType.ERROR, com.other.MessageType.ERROR);
        }}; 
    private static final Map<com.other.MessageType, pl.different.MessageType> REVERSE_MAPPING =
        new EnumMap<com.other.MessageType, pl.different.MessageType>(com.other.MessageType.class) {{
            put(com.other.MessageType.WARN, pl.different.MessageType.WARN);
            put(com.other.MessageType.INFO, pl.different.MessageType.INFO);
            put(com.other.MessageType.ERROR, pl.different.MessageType.ERROR);      
        }};

    private com.other.MessageType convertToInsurancePolisyMessageType1(pl.different.MessageType messageType) {
        return DIRECT_MAPPING.computeIfAbsent(messageType, key -> throw new IllegalArgumentException(messageType.name()));
    }

    private pl.different.MessageType convertToInsurancePolisyMessageType2(com.other.MessageType messageType) {
        return REVERSE_MAPPING.computeIfAbsent(messageType, key -> throw new IllegalArgumentException(messageType.name()));
    }
}

0 голосов
/ 27 марта 2019

Боюсь, что нет способа обойти какую-либо распечатку / отображение между значениями каждого входного MessageType и возвращаемого.

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

В дополнение к другим ответам, основанным на статических картах, которые, кстати, вполне хороши, если у вас есть контроль над кодом, возвращайте MessageType enum (т.е. вы разрабатываете такое enum). Я думаю, что вы должны рассмотреть возможность инкапсуляции преобразования в этом enum путем перегрузки одного и того же имени для каждого типа аргумента.

Здесь есть несколько вариантов ... Я лично предпочитаю of для названия. valueOf приемлемо, но так как valueOf (String) выдаст исключение NoSuchElementException, вы должны сохранить это поведение. Давайте придерживаться of здесь:

enum MessageType {
  WARN, INFO, ERROR;

  private static Map<pl.different.MessageType, MessageType> byPlDiffMType = 
      new EnumMap<>(Map.of(
          pl.different.MessageType.WARN, WARN,
          pl.different.MessageType.INFO, INFO,
          pl.different.MessageType.ERROR, ERROR
      ));

  private static Map<com.other.MessageType, MessageType> byCOthMType = 
      new EnumMap<>(Map.of(
          com.other.MessageType.WARNING, WARN,
          com.other.MessageType.INFO, INFO,
          com.other.MessageType.ERROR, ERROR
      ));

  public static MessageType of(pl.different.MessageType value) {
      return of(byPlDiffMType, value);
  }

  public static MessageType of(com.other.MessageType value) {
      return of(byCOthMType, value);
  }

  private static <V> MessageType of(Map<V, MessageType> map, V value) {
     final MessageType result = map.get(value);
     if (result == null) {
         throw new IllegalArgumentException();
     } else {
         return result;
     }
  }
}

Даже если у вас нет контроля над этим источником класса, вам, вероятно, лучше по производительности использовать EnumMap, а не обычные Map с (например, HashMap).

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

Единственный способ уменьшить линию - это сделать какое-то сопоставление через общие имена, добавив if s для тех, кто отличается, но я бы не советовал делать это, так как это молча сломалось бы с изменениями в будущем и вероятно, меньше "перформанс".

0 голосов
/ 27 марта 2019

Примерно так (с благодарностью RealSkeptic - извините, ваш комментарий появился после того, как я начал писать, но то же самое!):

public class DifferentMessageTypeConverter {
    public enum DifferentMessageType {
        WARNING, INFO, ERROR;
    }

    public enum InsurancePolicyMessageType {
        WARN, INFO, ERROR;
    }

    private static final Map<DifferentMessageType, InsurancePolicyMessageType> DIFF_TO_INS_MAPPING;

    static {
        DIFF_TO_INS_MAPPING = new HashMap<>();
        DIFF_TO_INS_MAPPING.put(DifferentMessageType.WARNING, InsurancePolicyMessageType.WARN);
        DIFF_TO_INS_MAPPING.put(DifferentMessageType.INFO, InsurancePolicyMessageType.INFO);
        DIFF_TO_INS_MAPPING.put(DifferentMessageType.ERROR, InsurancePolicyMessageType.ERROR);
    }

    public InsurancePolicyMessageType convertToInsurancePolisyMessageType1(DifferentMessageType dmt) {
        dmt = Optional.ofNullable(dmt)
                      .orElseThrow(() -> new IllegalArgumentException("dmt must not be null"));

        return Optional.ofNullable(dmt)
                       .map(DIFF_TO_INS_MAPPING::get)
                       .orElseThrow(() -> new IllegalArgumentException(messageType.name()));
    }
}
...