编辑: 从另一个问题,我提供了一个答案,有很多关于单例的问题/答案的链接:

所以我读了单身人士的帖子:好的设计还是拐杖? 争论仍在激烈进行。

我认为单例是一种设计模式(有好有坏)。 单例的问题不在于模式,而在于用户(对不起大家)。每个人和他们的父亲都认为他们可以正确地实施一个(从我所做的许多采访来看,大多数人都不能)。另外,因为每个人都认为他们可以实现正确的单例,所以他们滥用模式并在不合适的情况下使用它(用单例替换全局变量!)

所以需要回答的主要问题是:

什么时候应该使用单例 如何正确地实现单例

我对本文的希望是,我们可以在一个地方(而不是谷歌和搜索多个站点)收集何时(以及如何)正确使用Singleton的权威来源。同样合适的是列出反用法和常见的坏实现,解释为什么它们不能工作,以及对于好的实现来说它们的缺点。

所以开始行动吧: 我会举起我的手,说这是我用的,但可能有问题。 我喜欢“Scott Myers”在他的书《Effective c++》中对这个主题的处理。

使用单例的好情况(不多): 日志框架 线程回收池

/*
 * C++ Singleton
 * Limitation: Single Threaded Design
 * See: http://www.aristeia.com/Papers/DDJ_Jul_Aug_2004_revised.pdf
 *      For problems associated with locking in multi threaded applications
 *
 * Limitation:
 * If you use this Singleton (A) within a destructor of another Singleton (B)
 * This Singleton (A) must be fully constructed before the constructor of (B)
 * is called.
 */
class MySingleton
{
    private:
        // Private Constructor
        MySingleton();
        // Stop the compiler generating methods of copy the object
        MySingleton(MySingleton const& copy);            // Not Implemented
        MySingleton& operator=(MySingleton const& copy); // Not Implemented

    public:
        static MySingleton& getInstance()
        {
            // The only instance
            // Guaranteed to be lazy initialized
            // Guaranteed that it will be destroyed correctly
            static MySingleton instance;
            return instance;
        }
};

好的。让我们把一些批评和其他实现放在一起。 : -)


当前回答

正如其他人所注意到的,单例的主要缺点包括无法扩展它们,以及失去实例化多个实例的能力,例如用于测试目的。

单例对象的一些有用的方面:

延迟或预先实例化 适用于需要设置和/或状态的对象

但是,您不必使用单例来获得这些好处。您可以编写一个普通的对象来完成这项工作,然后让人们通过工厂(一个单独的对象)访问它。如果需要,工厂可以只考虑实例化一个,并重用它等等。同样,如果你对一个接口而不是一个具体的类编程,工厂可以使用策略,也就是说,你可以切换到和退出接口的各种实现。

最后,工厂可以使用依赖注入技术,如Spring等。

其他回答

但是当我需要像Singleton这样的东西时,我经常使用Schwarz Counter来实例化它。

我用Singletons作为面试测试。

当我让开发人员说出一些设计模式时,如果他们只能说出Singleton,他们就不会被录用。

在桌面应用程序中(我知道,只有我们这些恐龙才会写这些!),它们对于获得相对不变的全局应用程序设置是必不可少的——用户语言,帮助文件的路径,用户首选项等等,否则就必须传播到每个类和每个对话框中。

编辑-当然这些应该是只读的!

独生子女的真正缺点是他们打破了继承。你不能派生一个新的类来提供扩展的功能,除非你能访问引用单例的代码。因此,除了Singleton将使您的代码紧密耦合之外(可通过策略模式修复…)又名依赖注入),它也会阻止你关闭部分代码的修订(共享库)。

因此,即使日志记录器或线程池的示例也是无效的,应该由策略替换。

当初始化和object时有很多代码正在运行时,单例非常方便。例如,当你使用iBatis设置一个持久化对象时,它必须读取所有的配置,解析映射,确保它是正确的,等等。在开始编写代码之前。

如果每次都这样做,性能会大大降低。在单例中使用它,你只执行一次命中,然后所有后续调用都不必执行它。