我正在寻找一种更好的模式来实现这样的事情:
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; }
}
问题是访问enum
会导致副作用。假设 Bar
打开数据库连接等。因此,即使我只需要 VAL2
,我也必须支付设置 VAL1
的费用。
OTOH,bar
的值与 enum
紧密耦合。它就像一个静态属性,但 enum
没有延迟初始化。我可以将 Foo.getBar() 抽象化并使用匿名类,但是这样我每次都必须支付设置费用。
有没有一种廉价的方法来为 enum
的属性添加延迟初始化?
[编辑] 为了明确这一点:
-
getBar()
被调用了数百万次。速度一定快得让人眼花缭乱。
-
我们在这里谈论单例(就像enum
本身)。只能创建一个实例。
对于其他要点,单元测试应该能够覆盖此行为。
-
实例必须延迟创建。
我们尝试的一种解决方案是在 Spring 中将值注册为 beans:
<bean id="VAL1.bar" class="...." />
这允许我们在运行时指定值并在测试中覆盖它们。不幸的是,这意味着我们必须以某种方式将 ApplicationContext
注入到 enum
中。所以我们需要一个全局变量。 畏缩
更糟糕的是:在 getBar()
中查找值太慢了。我们可以同步
getBar()
并使用if(bar!= null)bar=context.get(name()+".bar");
代码> 来解决这个问题。
但是,有没有一种方法可以不使用此方法,并且与使用枚举值本身一样安全和快速呢?
I'm looking for a better pattern to implement something like this:
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; }
}
The issue is that accessing the enum
causes side effects. Say Bar
opens a DB connection and the like. So even if I just need VAL2
, I have to pay the price to setup VAL1
.
OTOH, the value of bar
is tightly coupled to the enum
. It's like an static attribute but enum
has no lazy initialization. I could make Foo.getBar()
abstract and use anonymous classes but then, I would have to pay the setup price every time.
Is there a cheap way to add lazy init for attributes of enum
s?
[EDIT] TO make this clear:
-
getBar()
is called millions of times. It must be blinding fast.
-
We're talking singleton here (just like enum
itself). Only a single instance must ever be created.
For additional points, unit tests should be able to override this behavior.
-
Instances must be created lazily.
One solution we tried as to register the values as beans in Spring:
<bean id="VAL1.bar" class="...." />
That allowed us to specify the values at runtime and override them in tests. Unfortunately, it means we have to inject the ApplicationContext
into the enum
somehow. So we need a global variable for that. cringe
What's worse: Looking up the value in getBar()
is way too slow. We can synchronize
getBar()
and use if(bar!= null)bar=context.get(name()+".bar");
to solve this.
But is there a way without this that is as safe and fast as using the enum
values themselves?
发布评论
评论(5)
只需用抽象工厂模式替换枚举即可。
UPD:您可以尝试这样的操作:
您可以尝试以某种方式优化同步部分,但这种方式可能会根据您的具体用例而有所不同。
Just replace the enum with an abstract factory pattern.
UPD: You can try something like this:
You can try to optimize the synchronization part in some way but that way can vary depending on your concrete use cases.
您可以使用执行延迟初始化的“值持有者”添加一级间接寻址:
现在,像这样调整枚举:
警告:因为这是不是线程安全的 ,可以创建任何
IBar
的任意多个实例。因此,这个解决方案不满足单例要求(OP中的#2)。更糟糕的是,getBar()
可以轻松返回对尚未初始化的IBar
实例的引用。You can add one level of indirection using a "value holder" which does the lazy initialization:
Now, adjust your enumeration like this:
Warning: Since this is NOT thread-safe, arbitrarily many instances of any
IBar
can be created. Therefore, this solution doesn't meet the Singleton requirement (#2 in the OP). And what is worse,getBar()
can easily return a reference to a not-yet-initialised instance of anIBar
.尝试在枚举中存储一个类而不是一个对象,当需要时,只需通过 Class.newInstance() 实例化它。
Try to store not an object but a class in your enum and when you need, just instantiate it via Class.newInstance().
以下是线程安全和延迟初始化,结合了两种模式:枚举单例 和 按需初始化支架。这是避免不必要的同步的唯一惰性方法,在抽象工厂模式发生在每个单个
getBar()
调用中,而在本例中它发生 >仅一次,如果静态嵌套类初始化,这是惰性的定义:The following is both thread-safe and lazy-initialized, combining two patterns: Enum Singleton and Initialization-On-Demand Holder. It is the only lazy way to avoid unnecessary synchronization, which in the case of Abstract Factory pattern occurs for every single
getBar()
call, whereas in this case it occurs only once in the event of Static Nested Class initialization, which is lazy by definition:根据弗拉基米尔的回答 - 这可以做到。它只会创建类对象,实例应该根据需要延迟创建:
Based on Vladimir's answer - this could do it. It will only create the class objects, the instances should be created lazily on demand: