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

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

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


当前回答

它模糊了关注点的分离。

假设您有一个单例,您可以从类中的任何位置调用此实例。您的类不再像它应该的那样纯粹。您的类现在将不再对其成员及其显式接收的成员进行操作。这会造成混乱,因为类的用户不知道该类所需的足够信息是什么。封装的整个思想是向用户隐藏方法的方式,但如果在方法内部使用了单例,则必须知道单例的状态才能正确使用该方法。这是反OOP。

其他回答

假设该模式用于模型的某个方面,而该方面是真正的单一模式,则该模式没有本质上的错误。

我认为这种反弹是由于它的过度使用,而这反过来又是因为它是最容易理解和实施的模式。

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

资源争夺。

如果你有一些资源

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

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

你需要一个单身汉。

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

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

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

首先,一个类及其合作者应该首先实现其预期目的,而不是专注于依赖对象。生命周期管理(当实例被创建并且超出范围时)不应该是类责任的一部分。对此,公认的最佳实践是创建或配置一个新组件,以使用依赖注入来管理依赖关系。

通常,软件变得更加复杂,所以有多个状态不同的Singleton类的独立实例是有意义的。在这种情况下,提交代码来简单地抓取单例是错误的。使用Singleton.getInstance()可能适用于小型简单系统,但当需要同一类的不同实例时,它无法工作/扩展。

任何类都不应该被认为是一个单独的类,而应该是它的用法或如何使用它来配置依赖项的应用程序。对于快速而令人讨厌的应用程序来说,这并不重要——只是简单的硬编码表示文件路径不重要,但对于更大的应用程序,需要使用DI以更合适的方式分解和管理这些依赖关系。

单例在测试中引起的问题是其硬编码的单一用例/环境的症状。测试套件和许多测试都是单独的,并且是独立的,与单例硬编码不兼容。

参见Wikipedia Singleton_pattern

一些人还认为它是一种反模式,他们认为它被过度使用,在实际上不需要类的唯一实例的情况下引入了不必要的限制。[1][2][3][4]

参考文献(仅文章中的相关参考文献)

^亚历克斯·米勒。我讨厌的模式#1:辛格尔顿,2007年7月^Scott Densmore。为什么单身汉是邪恶的,2004年5月^史蒂夫·耶格。单身汉被认为愚蠢,2004年9月^J.B.Rainsberger,IBM。2001年7月,明智地使用你的单身

Singleton不是关于单个实例!

与其他答案不同,我不想谈论Singleton有什么问题,而是想告诉你,如果使用得当,它们是多么强大和可怕!

问题:在多线程环境中,Singleton可能是一个挑战解决方案:使用单线程引导过程来初始化单例的所有依赖项。问题:很难模仿单身汉。解决方案:使用工厂模式进行模拟


您可以将MyModel映射到继承它的TestMyModel类,每当注入MyModel时,您都会得到TestMyModel instread。-问题:单线程可能会导致内存泄漏,因为它们从未处理过。解决方案:好吧,把它们处理掉!在你的应用程序中实现回调以正确处理一个单件,你应该删除所有链接到它们的数据,最后:从工厂中删除它们。

正如我在标题中所说的,singleton不是关于单个实例的。

singleton提高了可读性:您可以查看您的类,看看它注入了什么样的singleton,以确定它的依赖项是什么。singleton改进了维护:一旦你从一个类中删除了一个依赖项,你就删除了一些单例注入,你就不需要去编辑其他类的一个大链接,这些类只是移动了你的依赖项(这是我的臭代码@Jim Burger)Singleton提高了内存和性能:当应用程序中发生了一些事情,并且需要很长的回调链才能传递时,您正在浪费内存和性能,通过使用Singleton,您正在削减中间人,并提高性能和内存使用率(通过避免不必要的局部变量分配)。