Java枚举 - 在字段,抽象方法和类级别映射之间进行选择

mis*_*tor 6 java oop enums

我编写了一个Java枚举,其中值具有各种属性.这些属性可以通过以下任何方式存储:

使用字段:

enum Eenum {
  V1(p1),
  V2(p2);

  private final A attr;

  public A attr() { return attr; }

  private Eenum(A attr) {
    this.attr = attr;
  }
}
Run Code Online (Sandbox Code Playgroud)

使用抽象方法:

enum Eenum {
  V1 {
    public A attr() { return p1; }
  },

  V2 {
    public A attr() { return p2; }
  }

  public abstract A attr();
}
Run Code Online (Sandbox Code Playgroud)

使用班级地图:

enum Eenum {
  V1,
  V2;

  public A attr() { return attrs.get(this); }

  private static final Map<A> attrs;

  static {
    ImmutableMap.Builder<Eenum, A> builder = ImmutableMap.builder();
    builder.put(V1, p1);
    builder.put(V2, p2);
    attrs = builder.build();
  }
}
Run Code Online (Sandbox Code Playgroud)

我该如何决定何时选择哪个?

谢谢!

mis*_*tor 0

(我正在回答我自己的问题,以便我可以分享我在尝试时学到的一些东西。)

为了针对您的具体案例做出决定,您应该提出以下问题:

1:属性值是否涉及前向引用?

有时V1的属性可能需要引用V2,反之亦然。这种情况并不罕见。如果您正在处理这样的问题enum,方法 1 根本行不通。编译器会(正确地)抱怨非法的前向引用。可以使用其他两种方法中的任何一种。

现在,如果属性值的计算成本很高并且是一个常量,那么您希望只计算一次。使用方法 2,您必须为每个枚举值引入局部变量,并在那里缓存结果。这很冗长,但会给您带来更好的性能。对于方法 3,结果只计算一次,因此不需要做任何额外的工作。这比方法 2 更具可读性,但性能稍差。根据您的案例所保证的具体权衡,在这些之间进行设计。

2:我需要缓存结果吗?

请参阅上一个项目符号的第二段。

如果没有前向引用,也可以使用方法1。但如果属性计算涉及的计算很复杂,那么最好使用其他两种方法之一。

3:属性是否与所有枚举值相关?

如果没有,那么从逻辑上讲,您应该Map在此处使用 a 。即方法3。

4:某些枚举值的某些属性是否有默认值?

如果是这样,您可以使用所有三种方法,它们都提供不同的权衡。

使用方法 1:您将定义一个辅助构造函数,将属性初始化为默认值。如果有多个这样的属性,这可能不是一个可行的方法。

方法 2:这实际上就像 Peter Lawrey 上面建议的“第四种”方法。enum您将有一个方法返回主体中的默认值。并且某些枚举值将重写此方法以返回不同的值。这又是相当冗长的。

方法 3:只是效率较低。其他各方面都很好。