单例模式是GoF模式书中一个完全付费的成员,但最近它似乎被开发人员世界孤立了。我仍然使用了相当多的单线程,特别是对于工厂类,虽然你必须对多线程问题(像任何类一样)小心一点,但我不明白为什么它们如此糟糕。

Stack Overflow似乎特别假设每个人都认为Singleton是邪恶的。为什么?

请用“事实、参考资料或具体专业知识”来支持您的回答


当前回答

摘自Brian Button:

它们通常被用作全局实例,为什么如此糟糕?因为您将应用程序的依赖项隐藏在代码中,而不是通过接口公开它们。让一些东西全球化以避免传播是一种代码气味。他们违反了单一责任原则:因为他们控制自己的创作和生命周期。它们固有地导致代码紧密耦合。这使得在许多情况下,在测试中伪造它们相当困难。它们在应用程序的整个生命周期中携带状态。另一个对测试的打击,因为您可能会遇到一种需要订购测试的情况,这对于单元测试来说是一个很大的禁忌。为什么?因为每个单元测试都应该彼此独立。

其他回答

从纯粹主义的观点来看,单身汉是不好的。

从实践的角度来看,单例是开发时间与复杂性的权衡。

如果你知道你的应用程序不会有太大的变化,那么它们很好用。只要知道,如果您的需求以意外的方式发生变化(在大多数情况下这是很正常的),您可能需要重构。

单体有时也会使单元测试复杂化。

当几个人(或团队)达成类似或相同的解决方案时,就会出现一种模式。许多人仍然使用原始形式的单件或使用工厂模板(Alexandrescu的《现代C++设计》中有很好的讨论)。并发性和管理对象生存期的困难是主要障碍,前者很容易按照您的建议进行管理。

和所有的选择一样,辛格尔顿也有其沉浮的部分。我认为它们可以适度使用,特别是对于在应用程序寿命期内仍然存在的对象。事实上,它们类似于(而且很可能是)全球性的,这可能引发了纯粹主义者。

如果你使用得当且最少,单身汉并不是邪恶的。还有很多其他好的设计模式可以在某一点上替代单例的需求(也可以提供最佳结果)。但是一些程序员不知道这些好模式,在所有情况下都使用单例模式,这使得单例模式对他们来说是有害的。

摘自Brian Button:

它们通常被用作全局实例,为什么如此糟糕?因为您将应用程序的依赖项隐藏在代码中,而不是通过接口公开它们。让一些东西全球化以避免传播是一种代码气味。他们违反了单一责任原则:因为他们控制自己的创作和生命周期。它们固有地导致代码紧密耦合。这使得在许多情况下,在测试中伪造它们相当困难。它们在应用程序的整个生命周期中携带状态。另一个对测试的打击,因为您可能会遇到一种需要订购测试的情况,这对于单元测试来说是一个很大的禁忌。为什么?因为每个单元测试都应该彼此独立。

单身者在集群方面也很糟糕。因为这样,您的应用程序中就不再有“恰好一个单例”了。

考虑以下情况:作为开发人员,您必须创建一个访问数据库的web应用程序。为了确保并发数据库调用不会相互冲突,您可以创建一个线程保存SingletonDao:

public class SingletonDao {
    // songleton's static variable and getInstance() method etc. omitted
    public void writeXYZ(...){
        synchronized(...){
            // some database writing operations...
        }
    }
}

因此,您可以确定应用程序中只存在一个singleton,并且所有数据库都通过这一个也是唯一的SingletonDao。您的生产环境现在如下所示:

到目前为止一切都很好。

现在,考虑您想在集群中设置web应用程序的多个实例。现在,你突然有了这样的想法:

这听起来很奇怪,但现在您的应用程序中有很多单例。这正是单例不应该是的:它有很多对象。如果您想对数据库进行同步调用,如本例所示,这尤其糟糕。

当然,这是单例用法错误的一个例子。但是这个例子的信息是:你不能相信你的应用程序中只有一个单例实例,特别是在集群方面。