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

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

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


当前回答

它模糊了关注点的分离。

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

其他回答

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

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

它很容易(ab)用作全局变量。依赖于单态的类相对来说更难单独进行单元测试。

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

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

所以基本上:

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

而不是:

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

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

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

作者的一些对位词:

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

我的类别实例

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

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

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

单例模式本身不是问题。问题是,这种模式经常被使用面向对象工具开发软件的人所使用,而没有对OO概念的扎实掌握。当在这个上下文中引入单例时,它们往往会成长为不可管理的类,这些类包含了每个小用途的帮助器方法。

从测试的角度来看,单身也是一个问题。它们往往使孤立的单元测试难以编写。控制反转(IoC)和依赖注入是旨在以面向对象的方式解决这个问题的模式,这有助于单元测试。

在垃圾收集环境中,单体很快就会成为内存管理的问题。

还有多线程场景,单线程可能成为瓶颈和同步问题。