Java 将类限制为一个实例而不使用单例?

Java 将类限制为一个实例而不使用单例?,java,singleton,Java,Singleton,我不想使用singleton,但我不能允许我的类有多个实例 你认为这是一个好方法吗?如果不是,有什么更好的办法? public class SoundSystem { private static boolean instanceCreated = false; public SoundSystem() { if(instanceCreated) { throw new IllegalStateException("Only one i

我不想使用singleton,但我不能允许我的类有多个实例

你认为这是一个好方法吗?如果不是,有什么更好的办法?

public class SoundSystem {

    private static boolean instanceCreated = false;

    public SoundSystem() {
        if(instanceCreated) {
            throw new IllegalStateException("Only one instance can be created.");
        }

        instanceCreated = true;
    }
}

不,这不是个好办法

让我们举一个多线程上下文中的快速示例

线程1实例化
SoundSystem
if(instanceCreated)
返回false,然后将
instanceCreated
更改为true,调度程序中断线程1。现在,线程2还可以实例化
声音系统
,因为当时
isInstanceCreated
为false

但最后,两个线程将有一个不同的实例。

这是一个单实例,即使您没有以“传统”方式强制执行它。我不推荐这种方法,我认为你应该找到另一种方法

例如,为什么不在程序启动时创建一个
SoundSystem
实例呢?您不需要显式地强制其单一性,只需将该实例传递给需要访问声音系统的其他对象即可。另外,如果有一天需要,这还可以让您轻松获得对不同类型的
音响系统的支持(即使您不需要,这也是一个不错的额外好处)

最重要的是,如果您尝试初始化多个
音响系统
s,opal初始化本身会失败吗?如果不是,那么就没有理由设定人为的限制。如果是这样,那么您可以让opnal确定什么是错误,什么不是错误。但在任何情况下,如果您只创建一个实例并传递它,而不是让所有应用程序类自己查询实例,则不会有风险


小心别掉进这里的陷阱。单身汉并非天生邪恶,但由于某些原因,他们经常被误用,因此一般建议反对他们。通常有一种更干净的方法,这些更干净的方法通常会带来很多额外的好处。考虑一下您试图解决的实际问题/您试图避免的情况

如果您愿意将所有字段设置为最终字段,则可以使用枚举。不过,这也有一些“代码味道”。它可以防止多线程问题,但有一个限制,即所有
SoundSystem
实例变量都必须是最终变量

public enum SoundSystem {
    INSTANCE("Hello", "World");

    private final Object field1;
    private final Object field2;

    private SoundSystem(Object field1, Object field2) {
        this.field1 = field1;
        this.field2 = field2;
    }

    @Override
    public String toString() {
        return field1.toString() + "  " + field2.toString();
    }

    public Object getField1() {
        return this.field1;
    }

    public Object getField2() { 
        return this.field2;
    }

    //etc., etc.
}

然后,您可以使用
SoundSystem.INSTANCE
访问您的单件物品

您发布的解决方案允许各种各样的“比赛条件”。两个实体试图同时创建一个声音系统,结果可能都创建了一个实例


也许让SoundSystem的所有方法和变量都是静态的会让你得到你想要的,但是没有更多的信息就很难知道

您不想使用singleton,但您想要一个singleton。你说说你为什么不想使用singleton,你的意思是什么?好吧,我在很多地方读到过,singleton是一种代码味道,我不得不承认它不是很漂亮。我只想限制实例的数量。这是一个单例,即使你没有用更传统的符号来表示它。无论如何,您的逻辑是合理的,尽管不是线程安全的。更重要的是,这似乎有点代码味道。你能告诉我们你为什么要这么做吗?小心不要落入一个陷阱。“我只想限制实例的数量。”当数量为1时,这就是单例的定义。即使您以自己的特殊方式执行,如果您限制实例的数量,而该数量恰好是一个实例,它也是一个单实例。@MightyWork,那么为什么不在程序启动时创建一个类实例(不用担心整个单例强制)并将您创建的实例传递给使用它的对象呢?最重要的是,您可以让OpenAL负责报告任何多个初始化错误。作为奖励,如果有一天需要,这还可以让您轻松地放弃对不同类型的
音响系统的支持。如果您能就这个答案被否决的原因发表评论,那就太好了。我是来学习的。让所有的东西都是静态的是不可能的,因为我需要它来实现某些接口。。但是你有一个关于竞争条件的观点。谢谢你的回答。我在这里试图避免代码气味,而不是引入另一个,甚至更糟。是的,事实上是这样,但我想我最终会坚持使用静态块,从而完全避免这些问题。那么,你对在静态块中进行初始化有什么看法?这似乎是一个好方法,除非它有一些我不知道的缺点。@maghtypoke相同的意见!在多线程环境中,如果必须使用单线程,静态块是线程安全的方法。在单线程环境中,它本质上只是您正在做的事情的同义词。重构代码以在静态块中提供相同的功能只是以不同的方式表达相同的概念设计。所以我的观点是一样的;无论您如何强制执行,单例都是单例。你问了一个“好方法”,所以你似乎对概念设计方法感兴趣;静态块基本上与现在的方法相同。好的,我想我会同意。