为什么使用单例而不是静态方法?

Seb*_*ber 89 java singleton design-patterns

我从来没有找到关于帮助器/实用程序类的这些简单问题的良好答案:

为什么我要创建一个单例(无状态)而不是使用静态方法?

如果对象没有状态,为什么需要对象实例?

Hei*_*nzi 78

通常,单例用于将某种全局状态引入应用程序.(说实话,往往比实际需要更多,但这是另一个时间的主题.)

但是,有一些极端情况甚至无状态单例可能有用:

  • 您希望在可预见的未来将其扩展到州.
  • 出于某些特定技术原因,您需要一个对象实例.示例:C#或Java 语句的Synchonization对象.
    locksynchronized
  • 您需要继承,即,您希望能够使用相同的接口但不同的实现轻松地将您的单件替换为另一个.
    示例:Toolkit.getDefaultToolkit()Java中的方法将返回一个单例,其确切类型取决于系统.
  • 你想引用相等标记值.
    示例:DBNull.Value在C#中.

  • 虽然恕我直言的单身人士被误用**引入全球各州,但我会选择+1.单例的目的不是使对象全局可用,而是强制对象仅实例化一次.全球物体是必要的邪恶.除非确实需要,否则应该尽量不使用它们,因为它们通常会导致高耦合,SomeSingleton.getInstance().someMethod()遍布整个地方.:) (27认同)
  • "轻松替换你的单身"部分是我观点中最重要的一点.Rest非常接近静态类实现. (2认同)

tza*_*man 37

我可以看到使用无状态单例而不是静态方法类的情况,即依赖注入.

如果你有一个直接使用的辅助类实用程序函数,它会创建一个隐藏的依赖项; 你无法控制谁可以使用它,或者在哪里.通过无状态单例实例注入相同的帮助程序类,可以控制它的使用位置和方式,并在需要时替换它/模拟它/等.

使它成为单例实例只是确保您不再分配任何类型的对象(因为您只需要一个).


Seb*_*ber 15

实际上我发现这里没有提到另一个答案:静态方法更难测试.

似乎大多数测试框架都非常适合模拟实例方法,但是其中许多测试框架并没有以一种体面的方式处理静态方法的模拟.

  • 但Powermock似乎能够这样做 (2认同)

bac*_*dos 6

在大多数编程语言中,类都避开了很多类型系统.虽然一个类,其静态方法和变量是一个对象,但它往往不能实现接口或扩展其他类.因此,它不能以多态方式使用,因为它不能是另一种类型的子类型.例如,如果您有一个接口IFooable,这是其他类的几个方法签名所要求的,StaticFoo则不能使用类对象代替IFooable,而FooSingleton.getInstance()can(假设,FooSingleton实现IFooable).

请注意,正如我对Heinzi的回答所评论的那样,单例是一种控制实例化的模式.它取代new Class()Class.getInstance(),这使作者能够Class更好地控制实例,他可以使用它来防止创建不必要的实例.单例只是工厂模式的一个非常特殊的情况,应该这样对待.共同使用使其成为全球注册管理机构的特殊情况,而这通常最终会变得糟糕,因为全球注册管理机构不应该毫不客气地使用.

如果您计划提供全局辅助函数,那么静态方法就可以正常工作.该类不会作为类,而是作为命名空间.我建议,你保持高凝聚力,否则你可能会遇到最奇怪的耦合问题.

greetz
back2dos