在Java中实现单例设计模式的有效方法是什么?


当前回答

确保你真的需要它。在谷歌上搜索“singleton反模式”,看看反对它的一些论点。

我想这并没有什么本质上的问题,但它只是一种公开某些全局资源/数据的机制,因此请确保这是最好的方法。特别是,我发现依赖注入(DI)更有用,特别是如果您也在使用单元测试,因为DI允许您将模拟资源用于测试目的。

其他回答

如果您不需要延迟加载,那么只需尝试:

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();

    private Singleton() {}

    public static Singleton getInstance() { return Singleton.INSTANCE; }

    protected Object clone() {
        throw new CloneNotSupportedException();
    }
}

如果您希望延迟加载并且希望单例是线程安全的,请尝试双重检查模式:

public class Singleton {
    private static Singleton instance = null;

    private Singleton() {}

    public static Singleton getInstance() {
        if(null == instance) {
            synchronized(Singleton.class) {
                if(null == instance) {
                    instance = new Singleton();
                }
            }
        }
        return instance;
    }

    protected Object clone() {
        throw new CloneNotSupportedException();
    }
}

由于双重检查模式不能保证有效(由于编译器的一些问题,我对此一无所知),因此您也可以尝试同步整个getInstance方法或为所有单例创建注册表。

创建单例对象的各种方法:

根据约书亚·布洛赫的说法,埃努姆将是最好的。也可以使用双重检查锁定。甚至可以使用内部静态类。

忘记延迟初始化;这太有问题了。这是最简单的解决方案:

public class A {    

    private static final A INSTANCE = new A();

    private A() {}

    public static A getInstance() {
        return INSTANCE;
    }
}

在写它之前,真的要考虑一下为什么你需要一个单例。关于使用它们有一个准宗教的争论,如果你在Java中搜索单例,你很容易就会发现。

就我个人而言,出于许多原因,我尽量避免单身汉,其中大部分可以通过谷歌搜索单身汉找到。我觉得单身汉经常被虐待,因为他们很容易被每个人理解。它们被用作将“全局”数据引入OO设计的机制,因为它很容易绕过对象生命周期管理(或者真正思考如何从B内部实现a)。看看像控制反转(IoC)或依赖注入(DI)这样的事情,可以找到一个不错的中间地带。

如果你真的需要一个,那么Wikipedia有一个很好的例子来说明单例的正确实现。

对于JSE 5.0及以上版本,采用Enum方法。否则,使用静态单例持有者方法(Bill Pugh描述的一种延迟加载方法)。后一种解决方案也是线程安全的,不需要特殊的语言构造(即易失性或同步)。