如何使用switch语句为不同的输入类型创建通用方法

时间:2019-03-27 14:16:11

标签: java generics switch-statement refactoring

我正在尝试重构代码,因为我创建的方法非常相似。甚至智能都强调这一点。方法的目的是(使用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 个答案:

答案 0 :(得分:1)

好吧,毕竟您的切换方式对我没什么不好的:)

只需抛出一些替代方法即可使用地图:

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

答案 1 :(得分:0)

这样的事情(要归功于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()));
    }
}

答案 2 :(得分:0)

恐怕没有解决方法,可以在每个输入MessageType的值和返回的MessageType的值之间进行某种列表/映射。

考虑到名称非常相似,也许您可​​以尝试基于反射的方法...但是,如果这种名称更改,我认为这只会给问题带来麻烦,并且如果进行此转换会降低性能

要补充基于静态映射的其他答案,顺便说一句,如果您可以控制代码返回MessageType枚举(即您正在开发这种枚举),我认为您应该考虑封装转换在该枚举中,通过为每种类型的参数重载相同的名称。

这里有几种选择...我个人更喜欢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,但我不鼓励这样做,因为它会随着更改的进行而无声地中断并且“性能”可能更低。