Java中的Singleton模式和静态类有什么区别?

时间:2010-08-20 15:05:47

标签: java design-patterns

单身如何与仅填充静态字段的类不同?

12 个答案:

答案 0 :(得分:36)

几乎每次我写一个静态类时,我最终都希望将它实现为非静态类。考虑:

  • 可以扩展非静态类。多态性可以节省大量的重复。
  • 非静态类可以实现一个接口,当您想要将实现与API分离时,该接口可以派上用场。

由于这两点,非静态类使得为依赖它们的项目编写更可靠的单元测试成为可能。

然而,单例模式距离静态类只有半步之遥。您有点获得了这些好处,但是如果您通过`ClassName.Instance'直接在其他类中访问它们,那么您将创建一个访问这些好处的障碍。就像ph0enix指出的那样,使用依赖注入模式会更好。这样,可以告诉DI框架特定类是(或不是)单例。您可以获得模拟,单元测试,多态性以及更多灵活性的所有好处。

答案 1 :(得分:12)

让我总结一下:)

本质区别在于:单身的存在形式是一个对象,静态不是。这导致了以下几点:

  • Singleton可以扩展。静而不是。
  • 如果未正确实施,则单例创建可能不是线程安全的。静而不是。
  • Singleton可以作为对象传递。静而不是。
  • Singleton可以被垃圾收集。静而不是。
  • Singleton比静态类更好!
  • 更多信息,但我还没有意识到:)

最后但并非最不重要的是,每当你要实现一个单身人士时,请考虑重新设计你的想法,不使用这个上帝对象(相信我,你会倾向于把所有“有趣”的东西都放到这个班级)并使用一个名为“Context”的普通类,或类似的东西。

答案 2 :(得分:5)

一个单身人士可以懒惰地进行初始化。

答案 3 :(得分:3)

区别在于语言无关。 Singleton的定义是:“确保一个类只有一个实例并提供一个全局访问点。”一个只填充静态字段的类与单例不同,但在您的使用场景中它们可能提供相同的功能。但正如JRL所说,懒惰的启动是一个区别。

答案 4 :(得分:3)

我认为,重要的是面向对象编程中的“对象”。除少数情况外,我们应该限制使用静态类。那种情况是:

  1. 创建对象时没有意义。就像 java.lang.Math 的方法一样。我们可以像对象一样使用类。因为 Math 类方法的行为不依赖于要在此类中创建的对象的状态。
  2. 由多个对象方法共同使用的代码,未达到对象变量且可能被关闭的代码可以是静态方法
  3. 另一个重要的事情是单身是可扩展的。单身人士可以延长。在 Math 类中,使用final方法,避免了此类对象的创建和扩展。 java.lang.System 类也是如此。但是, Runtime 类是单个对象,而不是静态方法。在这种情况下,您可以为不同的目的覆盖 Runtime 类的继承方法。

    您可以延迟创建Singleton对象,直到需要(延迟加载)。但是,对于静态方法类,没有条件这样的东西。如果你到达该类的任何静态成员,该类将被加载到内存中。

    因此,静态方法类的最基本的好处是您不必创建对象,但如果使用不当,它将使您的代码从面向对象中删除。

答案 5 :(得分:2)

至少你可以更容易地用模拟或存根替换它来进行单元测试。但正如你所描述的那样,我并不是单身人士的忠实粉丝:它是伪装的全球变量。

答案 6 :(得分:2)

单例是一个只有一个实例的类,强制执行。该类可能具有状态(是的,我知道静态变量保持状态),并非所有成员变量或方法都需要是静态的。

变体将是这些对象的一小部分,如果所有方法都是静态的,这将是不可能的。

答案 7 :(得分:2)

单例类将有一个实例,通常每个类加载器只有一个实例。因此它可以有常规方法(非静态方法),并且可以在该特定实例上调用它们。

虽然只有静态方法的类,但实际上没有必要创建实例(因此大多数人/框架都会使这些类的类抽象化)。您将直接在类上调用方法。

答案 8 :(得分:1)

首先想到的是,如果你想使用只有静态方法和属性的类而不是单例,你必须使用静态初始化器来正确初始化某些属性。例如:

class NoSingleton {
  static {
    //initialize foo with something complex that can't be done otherwise
  }
  static private foo;
}

这将在类加载时执行,这可能不是你想要的。如果将它作为单例实现,你可以更好地控制整个shebang。但是我觉得在任何情况下使用单身都不是一个好主意。

答案 9 :(得分:0)

注意:这些示例都在C#中,因为这是我更熟悉的,但这个概念应该适用于Java。

忽略关于何时使用Singleton对象的争论,我所知道的一个主要区别是Singleton对象有一个可以传递的实例。

如果你使用静态类,你可以自己硬连接到特定的实现,并且无法在运行时改变它的行为。

使用静态类设计不佳:

public class MyClass
{
   public void SomeMethod(string filename)
   {
      if (File.Exists(filename))
        // do something
   }
}

或者,您可以让构造函数接受特定接口的实例。在生产中,您可以使用该接口的Singleton实现,但在单元测试中,您可以简单地模拟接口并改变其行为以满足您的需求(例如,使其抛出一些模糊的异常)。

public class MyClass
{
   private IFileSystem m_fileSystem;

   public MyClass(IFileSystem fileSystem)
   {
      m_fileSystem = fileSystem;
   }

   public void SomeMethod(string filename)
   {
      if (m_fileSystem.FileExists(filename))
         // do something
   }
}

这并不是说静态类总是坏的,只是不适合文件系统,数据库连接和其他低层依赖的东西。

答案 10 :(得分:0)

单例的一个主要优点是您可以实现接口并从其他类继承。有时你有一组单身人士都提供类似的功能,你想要实现一个共同的界面,但负责不同的资源。

答案 11 :(得分:0)

Singleton Class: Singleton Class是每个类加载器只能存在单个实例的类。

帮助程序类(仅包含静态字段/方法的类): 没有此类的实例。只有字段和方法可以作为常量或辅助方法直接访问。

blog中的这几行描述得非常好:

  

首先,Singleton模式非常好   如果你想创建一个有用   一个类的实例。为我的帮手   我们真的不想上课   实例化该类的任何副本。   你不应该使用的原因   Singleton类是因为这个   帮助类我们不使用任何   变量。单身人士会   如果它包含一组,那就很有用   我们只想要一组的变量   和那些使用的方法   变量,但在我们的帮助类中我们   不要使用除了之外的任何变量   传入(我们做出最后的)。   因此我不相信我们   想要一个单例实例,因为我们   不想要任何变量而我们不需要   希望任何人实例化这个类。   所以,如果你不想要任何人   实例化类,即   通常,如果你有某种   helper / utils类然后我用什么   我调用静态类,一个类   私有构造函数,仅限   由静态方法组成,没有任何   任何变量。