单例模式是GoF模式书中一个完全付费的成员,但最近它似乎被开发人员世界孤立了。我仍然使用了相当多的单线程,特别是对于工厂类,虽然你必须对多线程问题(像任何类一样)小心一点,但我不明白为什么它们如此糟糕。
Stack Overflow似乎特别假设每个人都认为Singleton是邪恶的。为什么?
请用“事实、参考资料或具体专业知识”来支持您的回答
单例模式是GoF模式书中一个完全付费的成员,但最近它似乎被开发人员世界孤立了。我仍然使用了相当多的单线程,特别是对于工厂类,虽然你必须对多线程问题(像任何类一样)小心一点,但我不明白为什么它们如此糟糕。
Stack Overflow似乎特别假设每个人都认为Singleton是邪恶的。为什么?
请用“事实、参考资料或具体专业知识”来支持您的回答
当前回答
首先,一个类及其合作者应该首先实现其预期目的,而不是专注于依赖对象。生命周期管理(当实例被创建并且超出范围时)不应该是类责任的一部分。对此,公认的最佳实践是创建或配置一个新组件,以使用依赖注入来管理依赖关系。
通常,软件变得更加复杂,所以有多个状态不同的Singleton类的独立实例是有意义的。在这种情况下,提交代码来简单地抓取单例是错误的。使用Singleton.getInstance()可能适用于小型简单系统,但当需要同一类的不同实例时,它无法工作/扩展。
任何类都不应该被认为是一个单独的类,而应该是它的用法或如何使用它来配置依赖项的应用程序。对于快速而令人讨厌的应用程序来说,这并不重要——只是简单的硬编码表示文件路径不重要,但对于更大的应用程序,需要使用DI以更合适的方式分解和管理这些依赖关系。
单例在测试中引起的问题是其硬编码的单一用例/环境的症状。测试套件和许多测试都是单独的,并且是独立的,与单例硬编码不兼容。
其他回答
摘自Brian Button:
它们通常被用作全局实例,为什么如此糟糕?因为您将应用程序的依赖项隐藏在代码中,而不是通过接口公开它们。让一些东西全球化以避免传播是一种代码气味。他们违反了单一责任原则:因为他们控制自己的创作和生命周期。它们固有地导致代码紧密耦合。这使得在许多情况下,在测试中伪造它们相当困难。它们在应用程序的整个生命周期中携带状态。另一个对测试的打击,因为您可能会遇到一种需要订购测试的情况,这对于单元测试来说是一个很大的禁忌。为什么?因为每个单元测试都应该彼此独立。
假设该模式用于模型的某个方面,而该方面是真正的单一模式,则该模式没有本质上的错误。
我认为这种反弹是由于它的过度使用,而这反过来又是因为它是最容易理解和实施的模式。
一些代码势利者看不起他们,认为他们只是一个荣耀的全球人。就像许多人讨厌goto语句一样,也有其他人讨厌使用全局的想法。我见过几位开发人员为了避免全局性而竭尽全力,因为他们认为使用全局性是失败的承认。奇怪但真实。
在实践中,Singleton模式只是一种编程技术,它是概念工具包的有用部分。有时你可能会发现它是理想的解决方案,所以使用它。但使用它只是为了吹嘘使用设计模式,就像拒绝使用它一样愚蠢,因为它只是一个全球性的。
因为它们基本上是面向对象的全局变量,所以通常可以用这样的方式设计类,这样就不需要它们了。
Singleton不是关于单个实例!
与其他答案不同,我不想谈论Singleton有什么问题,而是想告诉你,如果使用得当,它们是多么强大和可怕!
问题:在多线程环境中,Singleton可能是一个挑战解决方案:使用单线程引导过程来初始化单例的所有依赖项。问题:很难模仿单身汉。解决方案:使用工厂模式进行模拟
您可以将MyModel映射到继承它的TestMyModel类,每当注入MyModel时,您都会得到TestMyModel instread。-问题:单线程可能会导致内存泄漏,因为它们从未处理过。解决方案:好吧,把它们处理掉!在你的应用程序中实现回调以正确处理一个单件,你应该删除所有链接到它们的数据,最后:从工厂中删除它们。
正如我在标题中所说的,singleton不是关于单个实例的。
singleton提高了可读性:您可以查看您的类,看看它注入了什么样的singleton,以确定它的依赖项是什么。singleton改进了维护:一旦你从一个类中删除了一个依赖项,你就删除了一些单例注入,你就不需要去编辑其他类的一个大链接,这些类只是移动了你的依赖项(这是我的臭代码@Jim Burger)Singleton提高了内存和性能:当应用程序中发生了一些事情,并且需要很长的回调链才能传递时,您正在浪费内存和性能,通过使用Singleton,您正在削减中间人,并提高性能和内存使用率(通过避免不必要的局部变量分配)。