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

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

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


当前回答

Singleton是一种模式,可以像任何其他工具一样被使用或滥用。

单例的坏部分通常是用户(或者我应该说单例不适合用于它不适合做的事情)。最大的违规行为是使用单例作为假全局变量。

其他回答

我认为这种混乱是因为人们不知道Singleton模式的真正应用。我再怎么强调也不为过。Singleton不是包装全局变量的模式。Singleton模式只应用于确保在运行时存在给定类的一个且只有一个实例。

人们认为辛格尔顿是邪恶的,因为他们在全球范围内使用它。正是因为这种困惑,辛格尔顿被人看不起。请不要混淆Singleton和globals。如果用于预期用途,您将从Singleton模式中获得极大的好处。

参见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,您正在削减中间人,并提高性能和内存使用率(通过避免不必要的局部变量分配)。

垄断是魔鬼,具有非只读/可变状态的单态是“真正的”问题。。。

在阅读了jason的回答中提到的单身汉是病态的骗子之后,我发现了这个小花絮,它提供了单身汉经常被滥用的最佳例子。

全局不好,因为:a.导致命名空间冲突b.它以不正当的方式暴露了国家说到单身汉a.调用它们的显式OO方式可以防止冲突,因此a点不是问题没有国家的单身汉(像工厂一样)不是问题。具有状态的单体可以分为两类,即不可变或一次写入多个(配置/属性文件)。这些都不错。可变单光子,这是一种参考持有者,就是你所说的那些。

在上一篇声明中,他指的是博客中的“单身汉是骗子”的概念。

这如何适用于垄断?

要开始垄断游戏,首先:

我们首先制定规则,这样每个人都在同一页上比赛一开始,每个人都有平等的开始为了避免混淆,只提供了一组规则规则在整个比赛中不允许改变

现在,对于那些没有真正发挥垄断作用的人来说,这些标准充其量是理想的。垄断的失败是很难接受的,因为垄断是关于金钱的,如果你输了,你就必须费力地看着其他玩家完成比赛,而损失通常是迅速而致命的。因此,规则通常会在某个时刻被扭曲,以牺牲其他玩家的利益为代价,为某些玩家的利益服务。

所以你在和朋友鲍勃、乔和艾德玩垄断游戏。你正在迅速建立你的帝国,并以指数级的速度消耗市场份额。你的对手正在削弱,你开始闻到血腥味(比喻)。你的好友Bob把所有的钱都投入了尽可能多的低价值财产,但他的投资回报率并没有达到预期的水平。鲍勃,由于运气不好,落在了你的木板路上,从此退出了比赛。

现在,游戏从友好的掷骰子变成了严肃的生意。鲍勃已经成为失败的榜样,乔和埃德不想像“那个家伙”那样结束。因此,作为主角,你突然成为敌人。乔和埃德开始练习幕后交易,幕后资金注入,被低估的换房,以及任何削弱你作为一名球员的事情,直到他们中的一人上升到最高。

然后,不是他们中的一个获胜,而是整个过程重新开始。突然间,一套有限的规则变成了一个移动的目标,游戏退化为一种社交互动,这将构成自《幸存者》以来每一部高收视率真人秀的基础。为什么,因为规则正在改变,而且对于它们应该代表什么/为什么/什么没有共识,更重要的是,没有一个人做出决定。在这一点上,游戏中的每一个玩家都在制定自己的规则,随后就会出现混乱,直到其中两个玩家太累了,无法继续玩游戏,并慢慢放弃。

因此,如果一个游戏的规则书准确地代表了一个单身者,那么垄断规则书就是一个滥用的例子。

这如何适用于编程?

除了可变单例存在的所有明显的线程安全和同步问题之外。。。如果您有一组数据,能够由多个不同的源同时读取/操作,并且在应用程序执行的整个生命周期内都存在,那么现在可能是退一步问“我在这里使用的数据结构类型正确吗”的好时机。

就我个人而言,我见过程序员滥用单例,将其用作应用程序中某种扭曲的跨线程数据库存储。在直接处理代码之后,我可以证明这是一个缓慢的过程(因为需要所有线程锁来保证它的线程安全),也是一个噩梦(因为同步错误的不可预测/间歇性),而且几乎不可能在“生产”条件下进行测试。当然,本可以使用轮询/信令来开发一个系统,以克服一些性能问题,但这并不能解决测试问题,当一个“真正的”数据库已经能够以更健壮/可扩展的方式完成相同的功能时,又何必麻烦呢。

只有当您需要单例提供的内容时,单例才是一个选项。写一个对象的只读实例。同样的规则也应该级联到对象的财产/成员。