Java中的可配置枚举
我正在寻找一种更好的模式来实现如下内容:Java中的可配置枚举,java,enums,lazy-initialization,Java,Enums,Lazy Initialization,我正在寻找一种更好的模式来实现如下内容: public static enum Foo { VAL1( new Bar() ), VAL2( new FooBar() ); private final bar; private Foo( IBar bar ) { this.bar = bar; } public IBar getBar() { return bar; } } public interface Factory
public static enum Foo {
VAL1( new Bar() ),
VAL2( new FooBar() );
private final bar;
private Foo( IBar bar ) {
this.bar = bar;
}
public IBar getBar() { return bar; }
}
public interface Factory {
IBar getBar();
}
public class BarFactory implements Factory {
private IBar barInstance;
public synchronized IBar getBar() {
if (barInstance == null) {
barInstance = new Bar();
}
return barInstance;
}
}
public class FooBarFactory implements Factory {
private IBar barInstance;
public synchronized IBar getBar() {
if (barInstance == null) {
barInstance = new FooBar();
}
return barInstance;
}
}
public static enum Foo {
VAL1(new BarHolder() {
IBar createBar() { return new Bar(); }
)},
VAL2(new BarHolder() {
IBar createBar() { return new FooBar(); }
)};
private final BarHolder barHolder;
private Foo(BarHolder barHolder) {
this.barHolder = barHolder;
}
public IBar getBar() { return barHolder.getBar(); }
}
问题是访问enum
会产生副作用。说Bar
打开一个数据库连接等。因此,即使我只需要VAL2
,我也必须为设置VAL1
付出代价
另外,bar
的值与enum
紧密耦合。它类似于一个静态属性,但是enum
没有延迟初始化。我可以将Foo.getBar()
抽象化并使用匿名类,但是每次我都必须支付安装费用
有没有一种便宜的方法可以为enum
s的属性添加lazy init
[编辑]要明确这一点:
getBar()
被调用了数百万次。它一定很快就失明了
enum
本身一样)。只能创建一个实例
对于其他点,单元测试应该能够覆盖此行为
<bean id="VAL1.bar" class="...." />
这允许我们在运行时指定值,并在测试中重写它们。不幸的是,这意味着我们必须以某种方式将ApplicationContext
注入enum
。所以我们需要一个全局变量。畏缩
更糟糕的是:在getBar()
中查找值太慢了。如果(bar!=null)bar=context.get(name()+“.bar”),我们可以同步并使用代码>来解决这个问题
但是,有没有一种方法没有这个功能,可以像使用enum
值本身一样安全和快速?尝试在枚举中存储一个类而不是一个对象,并且在需要时,只需通过class.newInstance()实例化它
公共静态枚举Foo{
VAL1(巴级),
VAL2(FooBar.class);
私人最后一班;
privatefoo(Class只需用抽象工厂模式替换enum
UPD:您可以尝试以下方式:
public static enum Foo {
VAL1( new Bar() ),
VAL2( new FooBar() );
private final bar;
private Foo( IBar bar ) {
this.bar = bar;
}
public IBar getBar() { return bar; }
}
public interface Factory {
IBar getBar();
}
public class BarFactory implements Factory {
private IBar barInstance;
public synchronized IBar getBar() {
if (barInstance == null) {
barInstance = new Bar();
}
return barInstance;
}
}
public class FooBarFactory implements Factory {
private IBar barInstance;
public synchronized IBar getBar() {
if (barInstance == null) {
barInstance = new FooBar();
}
return barInstance;
}
}
public static enum Foo {
VAL1(new BarHolder() {
IBar createBar() { return new Bar(); }
)},
VAL2(new BarHolder() {
IBar createBar() { return new FooBar(); }
)};
private final BarHolder barHolder;
private Foo(BarHolder barHolder) {
this.barHolder = barHolder;
}
public IBar getBar() { return barHolder.getBar(); }
}
您可以尝试以某种方式优化同步部分,但这种方式可能会根据具体的用例而有所不同。您可以使用“值持有者”添加一级间接寻址,该值持有者执行延迟初始化:
abstract class BarHolder {
IBar bar;
abstract IBar createBar();
IBar getBar() {
if (bar == null) {
bar = createBar();
}
return bar;
}
}
现在,按如下方式调整枚举:
public static enum Foo {
VAL1( new Bar() ),
VAL2( new FooBar() );
private final bar;
private Foo( IBar bar ) {
this.bar = bar;
}
public IBar getBar() { return bar; }
}
public interface Factory {
IBar getBar();
}
public class BarFactory implements Factory {
private IBar barInstance;
public synchronized IBar getBar() {
if (barInstance == null) {
barInstance = new Bar();
}
return barInstance;
}
}
public class FooBarFactory implements Factory {
private IBar barInstance;
public synchronized IBar getBar() {
if (barInstance == null) {
barInstance = new FooBar();
}
return barInstance;
}
}
public static enum Foo {
VAL1(new BarHolder() {
IBar createBar() { return new Bar(); }
)},
VAL2(new BarHolder() {
IBar createBar() { return new FooBar(); }
)};
private final BarHolder barHolder;
private Foo(BarHolder barHolder) {
this.barHolder = barHolder;
}
public IBar getBar() { return barHolder.getBar(); }
}
警告:由于这是非线程安全的,因此可以创建任意多个IBar
实例。因此,此解决方案不满足单例要求(#OP中的2)。更糟糕的是,getBar()
可以根据Vladimir的回答轻松返回对尚未初始化的IBar实例的引用-这可以做到。它只会创建类对象,实例应根据需要延迟创建:
public static enum Foo {
VAL1(Bar.class),
VAL2(FooBar.class);
private Class<? extends IBar> clazz;
private IBar bar = null;
private Foo( Class<? extends IBar> clazz) {
this.clazz = clazz;
}
public IBar getBar() {
if (bar == null)
bar = clazz.newInstance();
}
return bar;
}
}
公共静态枚举Foo{
VAL1(巴级),
VAL2(FooBar.class);
私有类以下是线程安全的和惰性初始化的,结合了两种模式:和。这是唯一的惰性的方法,以避免不必要的同步,在模式发生的情况下,每个getBar()
调用,而在这种情况下,它只在初始化时发生一次,而初始化是通过以下方式进行的:
我认为这是最好的解决方案。你有代码吗?如何确保每个值只创建一次(像单例一样)?这并不能解决我的问题,因为每次调用getBar()
,它都会创建一个新实例。它只创建一次实例(请参见BarHolder.getBar())。不使用synchronize
,您能使此工作多线程吗?这是一种类似于原始值的访问(在循环中和代码中的任何地方都有数百万次)而且我担心成本。客户端如何确保每个值只创建一个实例?它们是否都必须在同一个枚举中?如果使用不同的枚举,每个枚举只能加载一个(或一个组)它们都属于同一个枚举。从逻辑/语义的角度来看,将它们分散在多个枚举上是没有意义的。