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

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

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

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

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

我对本文的希望是,我们可以在一个地方(而不是谷歌和搜索多个站点)收集何时(以及如何)正确使用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;
        }
};

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


当前回答

单例对象的问题不在于它们的实现。而是它们合并了两个不同的概念,这两个概念显然都不可取。

1)单例提供了对对象的全局访问机制。尽管在没有定义良好的初始化顺序的语言中,它们可能更线程安全或更可靠,但这种用法在道义上仍然相当于全局变量。它是一个用一些笨拙的语法修饰的全局变量(比如说,foo::get_instance()而不是g_foo),但它具有完全相同的目的(在整个程序中可访问的单个对象),并且具有完全相同的缺点。

2)单例防止一个类的多个实例化。据我所知,这种特性很少被添加到类中。这通常是一个更有语境的东西;很多被认为是独一无二的东西实际上只是碰巧是独一无二的。在我看来,更合适的解决方案是只创建一个实例——直到您意识到需要多个实例为止。

其他回答

Anti-Usage:

过度使用单例的一个主要问题是,该模式阻碍了可选实现的简单扩展和交换。类名在任何使用单例的地方都是硬编码的。

第一个例子不是线程安全的——如果两个线程同时调用getInstance,这个静态将是一个PITA。某种形式的互斥会有所帮助。

Alexandrescu的现代c++设计有一个线程安全的、可继承的泛型单例。

对于我的2p价值,我认为为你的单例对象定义生命周期是很重要的(当绝对有必要使用它们时)。我通常不让静态的get()函数实例化任何东西,把设置和销毁留给主应用程序的某个专用部分。这有助于突出单例程序之间的依赖关系——但是,正如上面强调的,如果可能的话最好避免它们。

答:

在以下情况下使用单例:

您需要在系统中有且只有一个类型的对象

在以下情况下不要使用单例:

你想要节省内存 你想尝试一些新的东西 你想炫耀你知道多少 因为其他人都在这么做(见wikipedia中的cargo cult程序员) 在用户界面小部件中 它应该是一个缓存 在字符串 在会话 我可以玩一整天

如何创建最佳单例:

越小越好。我是一个极简主义者 确保它是线程安全的 确保它永远不为空 确保只创建一次 懒惰还是系统初始化?符合您的要求 有时操作系统或JVM为你创建单例(例如,在Java中每个类定义都是单例) 提供析构函数或以某种方式计算出如何处理资源 使用较少的内存

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

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