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

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

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

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

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

我对本文的希望是,我们可以在一个地方(而不是谷歌和搜索多个站点)收集何时(以及如何)正确使用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)单例防止一个类的多个实例化。据我所知,这种特性很少被添加到类中。这通常是一个更有语境的东西;很多被认为是独一无二的东西实际上只是碰巧是独一无二的。在我看来,更合适的解决方案是只创建一个实例——直到您意识到需要多个实例为止。

其他回答

当我有一个封装大量内存的类时,我发现它们很有用。例如,在我最近开发的一款游戏中,我有一个影响映射类,它包含一个非常大的连续内存数组集合。我想在启动时全部分配,在关闭时全部释放,我肯定只想要它的一个副本。我还必须从很多地方访问它。我发现单例模式在这种情况下非常有用。

我相信还有其他的解决方案,但我觉得这个非常有用,而且很容易实现。

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

如何正确地实现单例

有一个问题我从未见人提起过,是我在之前的工作中遇到的。我们有在dll之间共享的c++单例,而通常的确保类的单个实例的机制就不起作用了。问题是每个DLL都有自己的一组静态变量,还有EXE。如果你的get_instance函数是内联的或者是静态库的一部分,那么每个DLL都会有它自己的“单例”副本。

解决方案是确保单例代码只定义在一个DLL或EXE中,或者创建一个具有这些属性的单例管理器来分配实例。

单例基本上让你在语言中拥有复杂的全局状态,否则就很难或不可能拥有复杂的全局变量。

Java特别使用单例变量作为全局变量的替代品,因为所有内容都必须包含在类中。最接近全局变量的是公共静态变量,它们可以像导入静态的全局变量一样使用

c++确实有全局变量,但是调用全局类变量的构造函数的顺序未定义。因此,单例可以让您推迟全局变量的创建,直到第一次需要该变量。

Python和Ruby等语言很少使用单例,因为您可以在模块中使用全局变量。

那么什么时候使用单例对象是好的/坏的呢?差不多就是什么时候使用全局变量是好是坏。

答:

在以下情况下使用单例:

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

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

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

如何创建最佳单例:

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