我已经写了一个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();
}
}
我应该如何决定何时更喜欢哪个?
谢谢!
我会做您认为最简单的那个。
通常,我不编写可以使用数据实现的代码。我会使用第一个。
我的实际用例具有一些与所有枚举值无关的属性
如果根据属性有意义,则可以使用这些方法的组合。
第四个选项是没有抽象方法。
enum Eenum {
V1 {
public A attr() { return p1; }
},
V2 {
public A attr() { return p2; }
},
V3, V4, V5, V6;
public A attr() { return defaultA; }
}
都不是。这样做:
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
,而且重要的是,要模拟测试更容易,尤其是如果您的枚举使用真实连接等。
。我授予您,所有这些仅在枚举是"不平凡"的情况下才适用。如果这只是一个普通的旧枚举,我同意这只是代码膨胀(我也很讨厌)
(我正在回答自己的问题,以便在尝试事物时分享一些我学到的东西。)
这是您应要求的问题,以决定您的具体情况:
1:属性值是否涉及前向引用?
有时V1
的属性可能需要引用V2
,反之亦然。这不是罕见的情况。如果您要处理这样的enum
,方法1根本不起作用。编译器将(正确)抱怨非法远期参考。其他两种方法都可以使用。
现在,如果属性值计算昂贵且常数,则您只想计算一次。使用方法2,您必须每个枚举值引入本地变量,并在那里缓存结果。这是冗长的,但会给您更好的表现。使用方法3,无论如何结果仅计算一次,因此不必做任何额外的工作。这是更可读的,但性能比方法2。根据您的案件中的特定交易,它们之间的设计。
。2:我需要缓存结果吗?
请参阅上一个子弹的第二段。
如果没有正向引用,则可以使用方法1。但是,如果属性计算中涉及的计算很复杂,那么您最好使用另一种方法之一。
3:属性是否与所有枚举值相关?
如果没有,那么从逻辑上讲,您应该在此处使用Map
。也就是说,方法3。
4:某些枚举值的某些属性是否有任何默认值?
如果是这样,您可以使用所有三种方法,并且它们都提供不同的权衡。
使用方法1:您将定义一个辅助构造函数,该辅助构造函数将属性初始化为默认值。如果有多个此类属性,这可能不是可行的方法。
使用方法2:这实际上就像彼得·劳瑞(Peter Lawrey)上面建议的"第四"方法。您将有一个方法返回enum
的主体中的默认值。一些枚举值将覆盖此方法以返回其他值。这再次是冗长的。
使用方法3:效率较低。以其他方式好。