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

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

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


当前回答

来自谷歌的Misko Hevery就这个话题发表了一些有趣的文章。。。

单身者是病态的骗子。有一个单元测试示例,说明了单身者如何难以找出依赖链并启动或测试应用程序。这是一个相当极端的虐待例子,但他提出的观点仍然有效:

单身者无非是全球国家。全局状态使您的对象可以秘密地获取未在其API中声明的内容,因此,Singleton会将您的API变成病态的骗子。

所有的Singleton都去哪儿了,这表明依赖注入使得向需要实例的构造函数提供实例变得容易,这减轻了第一篇文章中谴责的糟糕的全局Singleton背后的潜在需求。

其他回答

在我的头顶上:

它们加强了紧密耦合。如果您的单例驻留在与其用户不同的程序集上,那么如果没有包含单例的程序集,using程序集就永远无法运行。它们允许循环依赖,例如,程序集A可以有一个依赖于程序集B的单例,而程序集B可以使用程序集A的单例。所有这些都不会破坏编译器。

一些代码势利者看不起他们,认为他们只是一个荣耀的全球人。就像许多人讨厌goto语句一样,也有其他人讨厌使用全局的想法。我见过几位开发人员为了避免全局性而竭尽全力,因为他们认为使用全局性是失败的承认。奇怪但真实。

在实践中,Singleton模式只是一种编程技术,它是概念工具包的有用部分。有时你可能会发现它是理想的解决方案,所以使用它。但使用它只是为了吹嘘使用设计模式,就像拒绝使用它一样愚蠢,因为它只是一个全球性的。

单身者解决了一个(而且只有一个)问题。

资源争夺。

如果你有一些资源

(1) 只能有一个实例,并且

(2) 您需要管理单个实例,

你需要一个单身汉。

例子不多。日志文件是最大的文件。您不想只放弃一个日志文件。您希望正确刷新、同步和关闭它。这是必须管理的单个共享资源的示例。

你很少需要单身汉。他们之所以不好,是因为他们觉得自己是一个全球性的人,而且他们是GoF设计模式书的全额付费成员。

当你认为你需要一个全局,你可能犯了一个可怕的设计错误。

单线态的问题是范围增加,因此耦合的问题。不可否认,在某些情况下,您确实需要访问单个实例,并且可以通过其他方式实现。

我现在更喜欢围绕控制反转(IoC)容器进行设计,并允许容器控制生命周期。这为依赖于实例的类提供了好处,使它们不知道存在单个实例的事实。将来可以更改单例的生存期。我最近遇到的一个例子是从单线程到多线程的简单调整。

FWIW,如果你尝试单元测试它时它是一个PIA,那么当你尝试调试、修复或增强它时,它就会变成PIA。

还有一件关于单身汉的事,还没有人说过。

在大多数情况下,“singletony”是某个类的实现细节,而不是其接口的特征。控制容器的反转可能会对类用户隐藏此特性;您只需要将类标记为singleton(例如,在Java中使用@singleton注释),就可以了;IoCC将完成剩下的工作。您不需要提供对单例实例的全局访问,因为访问已经由IoCC管理。因此,IoC Singleton没有任何问题。

与IoC Singleton相反的GoF Singleton应该通过getInstance()方法在接口中暴露“singletony”,因此他们会受到上面所说的一切影响。