我编写了一个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();
}
}
我该如何决定何时选择哪个?
谢谢!
答案 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:效率低下。在其他方面都很好。