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

时间:2012-11-01 18:45:46

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

使用抽象方法:

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

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

  public abstract A attr();
}

使用班级映射:

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

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

谢谢!

3 个答案:

答案 0 :(得分:3)

我会做你认为最简单的那个。

一般情况下,我不会编写可以使用数据实现的代码。我会使用第一个。

  

我的实际用例有一些与所有枚举值无关的属性

如果在每个属性的基础上有意义,您可以使用这些方法的组合。

第四种选择是没有抽象方法。

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

  V2 {
    public A attr() { return p2; }
  }, 
  V3, V4, V5, V6;

  public A attr() { return defaultA; }
}

答案 1 :(得分:0)

没有一个。这样做:

interface HasAttr<T> {
    T attr();
}

enum Eenum implements HasAttr<A> {

    // use "fields" version - ideally with constructor version

    public A attr() {
        return field;
    }

}

此模式遵循基本Abstract Type设计模式,允许使用以下方法:

public void someMethod(HasAttr<A> hasAttr);  // pass anything that is HasAttr<a>

优先于固定类型:

public void someMethod(Eenum eenum); // locked into passing an Eenum

此外,重要的是,模拟测试更容易,特别是如果你的枚举使用真实连接等。

我授予你,所有这些只在枚举是“非平凡的”时才适用。如果它只是一个简单的旧枚举,我同意它只是代码膨胀(我也讨厌)

答案 2 :(得分:0)

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

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

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

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

现在,如果属性值计算成本高且常数不变,那么您希望它只计算一次。使用方法2,您必须为每个枚举值引入局部变量,并在那里缓存结果。这很冗长,但会给你更好的表现。使用方法3,结果无论如何只计算一次,因此不必进行任何额外的工作。这比读取方法更具可读性,但性能稍差2.根据您的具体情况进行设计。

2:我是否需要缓存结果?

参考前一篇文章的第二段。

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

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

如果没有,那么在逻辑上,你应该在这里使用Map。也就是说,接近3。

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

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

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

采用方法2:这实际上就像&#34;第四&#34;上面提到Peter Peter的建议。您将有一个方法返回enum主体中的默认值。并且一些枚举值将覆盖此方法以返回不同的值。这又是非常冗长的。

方法3:效率低下。在其他方面都很好。