【发布时间】:2011-02-15 10:36:54
【问题描述】:
对于这些关于帮助程序/实用程序类的简单问题,我从来没有找到好的答案:
- 为什么要创建单例(无状态)而不是使用静态方法?
- 如果对象没有状态,为什么还需要对象实例?
【问题讨论】:
-
不要想,因为我们谈论 2 种不同的语言,所以答案可能会有所不同,但感谢您的链接,在 java 中从未听说过“单态”一词
标签: java design-patterns singleton
对于这些关于帮助程序/实用程序类的简单问题,我从来没有找到好的答案:
【问题讨论】:
标签: java design-patterns singleton
根据 GoF 的书Design Patterns,“单例”一章,类操作与单例相比有以下缺点(我的粗体强调):
- 比类操作更灵活。 封装单例功能的另一种方法是使用类操作(即 C++ 中的静态成员函数或 Smalltalk 中的类方法)。但是这两种语言技术都使得很难改变设计以允许一个类的多个实例。此外,C++ 中的静态成员函数永远不是虚拟的,因此子类不能覆盖它们是多态的。
【讨论】:
通常,单例用于向应用程序引入某种全局状态。 (老实说,这通常不是真正必要的,但这是另一个话题。)
但是,在某些极端情况下,即使是 无状态 单例也是有用的:
lock 或 Java synchronized 语句的同步对象。
Toolkit.getDefaultToolkit() 方法将返回一个其确切类型的单例取决于系统。DBNull.Value。【讨论】:
对我来说“想要对象状态使用单例,想要函数使用静态方法”
这取决于你想要什么。每当您想要对象状态时(例如像 Null 状态而不是 null 或默认状态的多态性),单例是适合您的选择,而当您需要函数时使用静态方法(接收输入然后返回输出)。
我推荐单例的情况,它在实例化后应该总是相同的状态。它既不能克隆,也不能接收任何要设置的值(文件中的静态配置除外,例如 java 中的 properties 文件)。
附:这两者之间的性能以毫秒为单位不同,因此请先关注架构。
【讨论】:
在使用哪一个之间需要权衡取舍。单例可能有也可能没有状态,它们指的是对象。如果它们不保持状态并且仅用于全局访问,那么静态更好,因为这些方法会更快。但是如果你想利用对象和 OOP 概念(继承多态),那么单例更好。
考虑一个例子:java.lang.Runtime 是 java 中的一个单例类。此类允许对每个 JVM 进行不同的实现。每个 JVM 的实现是单一的。如果这个类是静态的,我们就不能传递基于 JVM 的不同实现。
我发现这个链接真的很有帮助:http://javarevisited.blogspot.com/2013/03/difference-between-singleton-pattern-vs-static-class-java.html?
希望对你有帮助!
【讨论】:
实际上,我找到了另一个此处未提及的答案:静态方法更难测试。
似乎大多数测试框架都非常适合模拟实例方法,但它们中的许多都不能很好地处理静态方法的模拟。
【讨论】:
单例不是无状态的,它持有全局状态。
我能想到使用 Singleton 的一些原因是:
【讨论】:
在大多数编程语言中,类都避开了很多类型系统。虽然具有静态方法和变量的类是一个对象,但它通常不能实现接口或扩展其他类。因此,它不能以多态方式使用,因为它不能是另一种类型的子类型。例如,如果你有一个接口IFooable,这是其他类的几个方法签名所需要的,那么类对象StaticFoo不能用来代替IFooable,而FooSingleton.getInstance()可以(假设FooSingleton实现IFooable)。
请注意,正如我对 Heinzi 的回答所评论的那样,单例是一种控制实例化的模式。它将new Class() 替换为Class.getInstance(),这使Class 的作者可以更好地控制实例,从而防止创建不必要的实例。单例只是工厂模式的一个非常特殊的情况,应该这样对待。普遍使用使它成为全局注册表的特殊情况,这通常以糟糕的结果告终,因为不应随意使用全局注册表。
如果您打算提供全局帮助函数,那么静态方法就可以正常工作。该类不会充当类,而只是充当名称空间。我建议,你保持高内聚,否则你可能会遇到最奇怪的耦合问题。
问候
back2dos
【讨论】:
我可以看到一个使用无状态单例而不是静态方法类的案例,即Dependency Injection。
如果你有一个你直接使用的实用函数的辅助类,它会创建一个隐藏的依赖;您无法控制谁可以使用它或在哪里使用它。通过无状态单例实例注入相同的帮助程序类可以让您控制它的使用位置和方式,并在需要时替换它/模拟它/等等。
使它成为一个单例实例只是确保您不会分配超过必要类型的任何对象(因为您只需要一个)。
【讨论】: