7

我编写了一个 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<Eenum, A> attrs;

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

我应该如何决定何时更喜欢哪个?

谢谢!

4

3 回答 3

3

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

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

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

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

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

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

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

  public A attr() { return defaultA; }
}
于 2012-11-01T18:49:38.507 回答
0

这些都没有。做这个:

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

enum Eenum implements HasAttr<A> {

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

    public A attr() {
        return field;
    }

}

此模式遵循基本的抽象类型设计模式,它允许以下方法:

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

优先于固定类型:

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

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

我承认,所有这一切都只适用于枚举“非平凡”的情况。如果它只是一个普通的旧枚举,我同意它只是代码膨胀(我也讨厌)

于 2012-11-01T18:51:08.697 回答
0

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

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

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

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

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

2:我需要缓存结果吗?

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

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

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

如果不是,那么从逻辑上讲,您应该在Map这里使用 a 。也就是方法3。

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

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

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

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

使用方法3:效率较低。其他方面都很好。

于 2012-11-04T00:00:56.860 回答