【问题标题】:when is a singleton class preferred over a class that has only static methods?什么时候单例类比只有静态方法的类更受欢迎?
【发布时间】:2011-09-21 01:16:24
【问题描述】:

什么时候单例类比只有静态方法和私有默认构造函数的类更受欢迎?

请投票。

【问题讨论】:

  • 你可以有一个单例的实例,而你的其他类不能实例化。
  • static class vs singleton class 的可能重复项
  • @Joe 不是重复的。 Java中只有内部类可以是static,所以这与问题无关。
  • @NullUserExceptionఠ_ఠ - 感谢您的澄清。
  • 为什么是近距离投票?请解释。如果我在每个问题前加上“关于什么是最佳实践”,那么每个意见问题都会变成事实问题。它不会改变问题的性质。

标签: java singleton


【解决方案1】:

在初始化发生时使用单例更好地控制。 对于静态类,任何初始化都必须在类加载时进行,而您几乎无法控制。例如,对静态最终成员的简单引用将触发类加载。使用单例,初始化可以很容易地推迟到很久以后——通常是第一次使用。

延迟初始化的原因可能是:

  • 它很贵,而且你并不总是需要它来上课
  • 在初始化其他资源(例如,数据库连接)之前,您无法进行初始化。在这种情况下,延迟实例化的单例通常会在没有任何显式控制的情况下提供正确的操作顺序 - 如果在其他资源初始化之后才引用它,那么一切都是免费的。

使用单例来提高可测试性。如果您需要制作单例的某种模拟对象(广义上)以测试其客户端,一种方法是使用一个接口,并提供一个不同类但实现相同接口的测试单例。

使用单例也使初始化测试更容易。

当您可能需要调试初始化时使用单例。静态初始化的堆栈跟踪可能令人费解。调试也可能令人费解。如果类提前加载,它可能会在 main() 中第一行的断点被命中之前中断。

【讨论】:

    【解决方案2】:

    什么时候单例类比只有静态方法和私有默认构造函数的类更受欢迎?

    当您需要一个实例时。例如,作为方法参数传递。

    【讨论】:

    • 您的意思是限制对仅接收引用副本的对象的访问?这似乎不是一个大问题,因为单例应该只用于系统范围的资源。如果它是系统范围的,那么一点隐私是很好的,但我认为没有太大的价值。我想知道这是否是喜欢单例的唯一原因。
    • 这也是为什么在正确的 OO 中很少使用和讨厌单例的原因。
    【解决方案3】:

    只有静态方法的主要原因是当您只需要一个工具箱将一些功能打包在一起时。

    我使用单例主要有两个原因:

    1. 构造对象确实很昂贵(时间或内存),并且 我只想做一次。
    2. 与类关联的数据 类的每个实例都必须相同。

    【讨论】:

    • 有效点,但您可以在静态方法中构建昂贵的对象并将其存储在静态字段中。只会有一份。
    【解决方案4】:

    如果您有一些需要存储的状态,那么单例就是要走的路。例如,如果您的类需要从属性文件中加载一些配置。

    【讨论】:

    • 静态方法访问的静态字段也可以存储状态,即使您无法实例化类。这可能很明显,也可能不明显,但你可以编写一个小类来证明它。
    • @broiyan 当然可以,但不一定可取。让我们以我给出的示例为例:加载属性文件。对于不了解需要调用静态方法来设置属性文件才能开始使用其他方法的类的用户来说,这可能会造成混淆。在创建实例时加载属性文件的单例中,用户没有机会犯此错误。
    • 在实用程序类中,该方法只能在静态初始化程序中调用。参见例如 stackoverflow.com/questions/2027244/…stackoverflow.com/questions/4362911/…
    • @broiyan 换句话说,即使单例接受了一些初始状态,它仍然可以是不可变的。如果您通过静态方法更改静态字段,则情况并非如此。
    • @BalusC 如果直到运行时才知道属性文件的位置,那么在我看来,使用静态初始化程序并不是最优雅的解决方案。
    【解决方案5】:

    静态方法不是动态的,这与单例类实例有很大不同。因此,如果您需要从一个类扩展并覆盖某些方法,则第二种方法将不起作用。

    对于第二种方式,你可能需要使用一些可能导致内存泄漏的静态引用。

    【讨论】:

      【解决方案6】:

      我想说单例类只在一种情况下更受欢迎:当您有一些系统范围的配置要存储时,很少(如果有的话)需要刷新。

      作为我的意思的一个例子,我的一个应用程序中有一个单例模式,它代表用户互联网连接的 NAT 设备。此应用程序旨在供桌面使用,因此很少(如果有的话)看到互联网连接发生变化。假设用户可以将他们的笔记本电脑带到一个新的位置,这将会改变;但是,有一种方法可以在此事件中重新创建状态,但这是一种很少更改的状态,可能需要几秒钟才能初始化。

      这需要保持昂贵、不经常更改和全局适用的状态,最好通过应用程序范围的 bean(我的首选)或单例模式 bean 来完成。静态方法不能很好地保留这种状态,尽管您也可以使用静态字段来完成此操作以制作伪单例。 (不确定是否有更好的名称 - 可能)

      一般来说,如果可以避免的话,我的建议是不要使用类似单例的模式,因为这会使重用变得更加困难。如果您使用的是 CDI 框架,请将您的 bean 限定在应用程序级别,以便于重用。 (这可能与您无关 - 如果不是,您可以放心地忽略此建议)

      【讨论】:

      • 这主要是见仁见智,但我个人从来没有将任何会在未来任何时候发生变化的东西放入静态字段中。 (尤其是公共静态字段)我对此的推理是,它本质上创建了一个全局变量,并且很容易以覆盖相同数据的不同代码片段结束,当它们弹出时导致诊断错误真正令人头疼.见c2.com/cgi/wiki?GlobalVariablesAreBad
      猜你喜欢
      • 2017-08-04
      • 1970-01-01
      • 1970-01-01
      • 2023-03-08
      • 2013-08-22
      • 2019-06-11
      • 2020-10-25
      • 1970-01-01
      • 2014-10-15
      相关资源
      最近更新 更多