是否有理由在 Java 的另一个类中保留对 Singleton 实例的引用?

发布于 2024-12-01 00:11:20 字数 585 浏览 1 评论 0原文

这可能是一个非常愚蠢的问题,但今天早些时候我遇到了一些代码,其中外部类存储对 Singleton 类实例的引用(在私有字段中),并且使用此引用而不是从 Singleton 类获取实例每次。

起初,它对我来说看起来是糟糕的设计,因为它无缘无故地向类添加了一个字段,但是还有其他原因为什么你不应该这样做(或者应该这样做)?

小代码示例来说明:

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();
    }
}

This is probably a pretty dumb question, but earlier today I ran into some code where an external class was storing a reference to a Singleton class instance (in a private field), and was using this reference instead of getting the instance from the Singleton class every time.

At first it looked like bad design to me, because it adds a field to a class for nothing, but is there another reason why you shouldn't do this (or should do this)?

Small code example to illustrate:

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();
    }
}

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

笑看君怀她人 2024-12-08 00:11:20

在这个例子中,不,没有任何好处。

但是,如果您使用依赖项注入,其中您的类将其依赖项作为构造函数参数,则传入单例实例可能非常有用,在这种情况下,您别无选择,只能存储引用。

In this example, no, there is no benefit.

However, if you are using dependency injection where your class takes its dependencies as constructor arguments, passing in a singleton instance could be very useful, and in that case you would have no option but to store the reference.

我乃一代侩神 2024-12-08 00:11:20

我想到的第一个原因是可以轻松地替换为其他对象,即实现公共接口或扩展公共超类的对象。

此外,如果由不同的类加载器加载,则可能存在单例的两个实例。

此外,虽然不完全符合单例模式的精神,但它可以用于存储对单例对象的旧实例的引用。

The first reason that comes to mind is to make it easy to substitute with some other object, one that implements a common interface or extends a common superclass.

In addition, it is possible that two instances of a singleton exist if loaded by different class loaders.

Also, though not exactly in he spirit of the singleton pattern, it could be used to store a reference to an old instance of the singleton object.

—━☆沉默づ 2024-12-08 00:11:20

如果您可以保证给定的单例确实是单例,那么这种方法将会起作用。在更复杂的环境中,它可能会失败,例如:

public class Singleton {
    private static Singleton instance = new Singleton();

    public static Singleton instance() {

        if (someCondition == true) {
            Singleton.instance.close() // close the object
            Singleton.instance = new Singleton();
        }

        return Singleton.instance;
    }
}

上面的示例并不是真正的单例,但它会破坏您提供的代码,因为新引用已分配给实例。如果您在不了解/访问外部库的内部行为的情况下使用外部库,则可能会出现这些问题。

我会避免“缓存”对单例的引用。

If you can guarantee that the given singleton really is a singleton this approach will work. In a more complex environment it may fail, e.g.:

public class Singleton {
    private static Singleton instance = new Singleton();

    public static Singleton instance() {

        if (someCondition == true) {
            Singleton.instance.close() // close the object
            Singleton.instance = new Singleton();
        }

        return Singleton.instance;
    }
}

The above example is not really a singleton, but it will break the code you provided as a new reference has been assigned to instance. Those problems may occur if you use external libraries without understanding/access to their internal behaviour.

I'd avoid 'caching' a reference to a singleton.

八巷 2024-12-08 00:11:20

实际上,我认为这样做有一些好处,因为如果您使用带有构造函数的枚举来管理静态引用,它将在启动时初始化(如类加载时),并且此后永远不会更改。

这可能有利于分离永久生成类,这可能会改善对存在问题的容器的热部署。但我不知道事实是否如此。

不利的一面是,如果枚举正在进行初始化,您可能会失去静态引用的生命周期管理。

更好的解决方案是通常避免像这样的静态单例并依赖依赖注入或 AOP(Google Spring 的 @Configurable)。

Actually I can seem some benefit in this in that if you are using an enum with a constructor to manage the static reference it will be initialized on startup (like on class load) and can never change after that.

This can be possible beneficial for separating out permgen classes which may improve hot deploying to containers where that is an issue. However I have no idea if this is actually the case.

On the negative side you might loose lifecycle management of the static reference if the enum is doing the initialization.

The better solution is to generally avoid static singletons like this and rely on dependency injection or AOP (Google Spring's @Configurable).

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文