是否有理由在Java中的另一个类中保留对单例实例的引用?
这可能是一个相当愚蠢的问题,但今天早些时候,我遇到了一些代码,其中外部类存储对单例类实例的引用(在私有字段中),并使用此引用,而不是每次都从单例类获取实例
起初,我觉得它的设计很糟糕,因为它在类中添加了一个字段,但有没有其他原因不应该这样做(或者应该这样做)
小代码示例来说明:
enum SomeSingletonObject {
INSTANCE;
public void someMethod() {...}
}
class AnotherObject {
private SomeSingletonObject sso;
public AnotherObject() {
this.sso = SomeSingletonObject.INSTANCE;
}
public void someMethod() {
sso.someMethod();
// instead of
// SomeSingletonObject.INSTANCE.someMethod();
}
}
# 1 楼答案
如果您可以保证给定的单例确实是一个单例,那么这种方法将起作用。在更复杂的环境中,它可能会失败,例如:
上面的示例并不是一个真正的单例,但它将破坏您提供的代码,因为新引用已分配给
instance
。如果使用外部库而不了解/访问它们的内部行为,则可能会出现这些问题我会避免“缓存”对singleton的引用
# 2 楼答案
想到的第一个原因是使它易于替换为其他对象,即实现公共接口或扩展公共超类的对象
此外,如果由不同的类装入器装入,则可能存在两个单例实例
此外,尽管不完全符合单例模式的精神,但它可以用于存储对单例对象的旧实例的引用
# 3 楼答案
在这个例子中,没有,没有好处
但是,如果您使用依赖项注入,而您的类将其依赖项作为构造函数参数,那么传入一个单例实例可能非常有用,在这种情况下,您将别无选择,只能存储引用
# 4 楼答案
实际上,我在这方面似乎有些好处,因为如果您使用带有构造函数的枚举来管理静态引用,它将在启动时初始化(就像在类加载时一样),并且在启动后永远不会更改
这可能有助于分离permgen类,这可能会改进容器的热部署,因为这是一个问题。但我不知道事实是否如此
消极的一面是,如果枚举正在进行初始化,您可能会失去静态引用的生命周期管理
更好的解决方案通常是避免这样的静态单例,并依赖依赖依赖注入或AOP(Google Spring的@Configurable)