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

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

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


当前回答

我不打算评论善/恶的论点,但自从春天来临以来,我就没有使用过它们。使用依赖注入几乎消除了我对单例、服务定位器和工厂的需求。我发现这是一个更加高效和干净的环境,至少对于我所做的工作类型(基于Java的web应用程序)来说是如此。

其他回答

Chris Reath最近在《无注释编码》杂志上发表的关于此主题的文章。

注意:无注释编码不再有效。但是,链接到的文章已被其他用户克隆。

Link

作者的一些对位词:

如果你将来需要让班级不再单身,你就会陷入困境一点也不——我当时使用的是一个数据库连接单例,我想将其转换为一个连接池。请记住,每个单例都是通过标准方法访问的:

我的类别实例

这类似于工厂方法的签名。我所做的只是更新实例方法以返回池中的下一个连接,无需进行其他更改。如果我们没有使用单例的话,那就更难了。

单身汉只是花式的全球明星这一点无可厚非,但所有静态字段和方法也是如此——从类而不是实例访问的任何东西本质上都是全局的,我看不出静态字段的使用有多大阻碍?

并不是说单身汉很好,只是反驳了这里的一些“传统智慧”。

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

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

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

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

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

单线图的一个相当糟糕的地方是,你不能很容易地扩展它们。如果你想改变他们的行为,你基本上必须构建某种装饰模式或类似的东西。此外,如果有一天你想用多种方式来做这一件事,那么改变可能会很痛苦,这取决于你如何布局代码。

需要注意的一点是,如果您确实使用了单体,请尝试将它们传递给需要它们的人,而不是让他们直接访问。。。否则,如果您选择使用多种方式来完成单例所做的事情,那么如果每个类都直接访问单例,那么很难进行更改,因为每个类都嵌入了一个依赖项。

所以基本上:

public MyConstructor(Singleton singleton) {
    this.singleton = singleton;
}

而不是:

public MyConstructor() {
    this.singleton = Singleton.getInstance();
}

我认为这种模式被称为依赖注入,通常被认为是一件好事。

就像任何模式一样。。。思考它,并考虑它在给定情况下的使用是否不合适。。。规则通常是被打破的,模式不应该随意应用。