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

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

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


当前回答

Singleton不是关于单个实例!

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

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


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

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

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

其他回答

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

资源争夺。

如果你有一些资源

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

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

你需要一个单身汉。

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

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

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

因为它们基本上是面向对象的全局变量,所以通常可以用这样的方式设计类,这样就不需要它们了。

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

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

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

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

我想谈谈公认答案中的4点,希望有人能解释我为什么错了。

为什么在代码中隐藏依赖项不好?已经有几十个隐藏的依赖项(C运行时调用、OS API调用、全局函数调用),单例依赖项很容易找到(搜索instance())。“使某个东西全局化以避免传递它是一种代码气味。”为什么不传递某个东西以避免使其成为单例代码气味?如果您通过调用堆栈中的10个函数传递一个对象,只是为了避免一个单例,那么这样做好吗?单一责任原则:我认为这有点模糊,取决于你对责任的定义。一个相关的问题是,为什么将这个特定的“责任”添加到一个班级中很重要?为什么将一个对象传递给一个类比将该对象作为类内的单例使用更紧密地耦合?为什么会改变国家的持续时间?单例对象可以手动创建或销毁,因此控件仍然存在,您可以使其生存期与非单例对象的生存期相同。

关于单元测试:

并非所有的类都需要是单位已测试并非所有需要成为单元的类测试需要更改单例的实现如果它们确实需要进行单元测试确实需要改变实施方式,很容易从使用singleton来实现通过依赖项传递给它的singleton注射

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

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