【问题标题】:Are there cases where a singleton is the best option?是否存在单例是最佳选择的情况?
【发布时间】:2009-01-16 08:50:41
【问题描述】:

这个网站上有很多关于为什么应该避免单例的讨论,但是在任何情况下单例是有意义的并且是最好的选择吗?

我认为单例是最佳选择的一个例子是在实现Identity Map 时,您需要跟踪已经从映射层中的数据库加载的所有模型。在这种情况下,重要的是映射实际上是全局的,以便所有客户端代码使用映射的相同实例并且它们都访问相同的加载模型列表。最简单的解决方案似乎是将类实现为单例(或静态方法)。这是最好的方法还是有其他方法?

还有其他情况可以使用单例还是总是不好?

【问题讨论】:

    标签: design-patterns oop singleton


    【解决方案1】:

    this thread

    【讨论】:

      【解决方案2】:

      单身人士确实有其用途。我将它们的用处总结为:

      “Singleton 应该用于表示对象,根据基本设计或要求,最多可以有一个实例;并且存在与该对象相关联的数据或资源,这会产生可衡量的成本。”这就是我的意思。

      1) 你不应该在有很多东西的情况下使用单例,但我们碰巧只对其中一个感兴趣。如果系统中可能有两个,则显式实例化一个。

      2) Singleton 的许多用途都可以用一个包含所有静态方法和数据的类来代替。如果您可以在不影响性能的情况下执行此操作,请执行此操作。

      3) 如果设置对象的成本很高,则应考虑使用 Singleton:例如,如果它是需要初始化的物理资源,或者它依赖于需要初始化的某个查找表。如果是这种情况,您可以使用 Singleton 将初始化成本推迟到第一次使用该对象,而静态类通常会在应用程序启动时进行初始化。如果该对象从未被使用过,则您永远不会支付初始化成本。

      【讨论】:

        【解决方案3】:

        当您只需要一个实例并希望通过设计强制执行时,应使用单例。它不应使用,因为它会引起全局副作用

        在您的情况下,我认为这是有道理的,因为您只想限制该类的一个实例。

        【讨论】:

          【解决方案4】:

          在不允许静态接口成员的语言中使用单例(和类似的) - 例如在 .NET 中。通过提供单例,您就有了一个可以将接口作为实例提供的实例。所以在 .NET 中,示例可能是:

          • Comparer<T>.Default - 提供一个 IComparer<T> 用于排序的实现 T
          • EqualityComparer<T>.Default - 为散列/相等测试提供 IEqualityComparer<T> 实现 T

          这是达到目的的手段;这不是我们想要做的,只是一个合理的“如何”。

          就“身份映射”示例而言,我个人更愿意将其保留在一个实例上,并使该实例可用于我的所有代码。除此之外,如果您可以丢弃测试之间的映射,或者具有灵活性(稍后)同时拥有多个身份映射,它有助于可测试性。

          【讨论】:

            【解决方案5】:

            考虑一下您希望将应用程序中的不同事件记录到单个文件的情况。在这种情况下,单例类 Log 将很有用。由于应用程序的不同部分将访问 Log 类的同一个实例。

            【讨论】:

              【解决方案6】:

              单身人士确实有其用途。他们也有自己的弊端,有很多理由不喜欢他们,或者他们让测试变得困难。

              这是对单例模式的一个小小的辩护。

              有时,程序需要代表真正独特的事物或与之交互。一个例子是物理资源。例如,您不能拥有多个“标准输出”。以及 OS 进程的表示(例如 J2ME 的 Midlet)。

              单例就像使用类/接口进行封装一样,对原本是裸全局变量的这些好处是值得的。

              【讨论】:

                【解决方案7】:

                当您使用 Web 编程时,单例是有意义的:您通常只需要每个请求一个页面输出类的实例,以及一个用户对象。但数据库不同 - 实现权限分离是需要多个 db 对象的一个​​很好的理由。

                【讨论】:

                  【解决方案8】:

                  我个人的指导方针是,如果您之后可以实例化一个类的一个对象,则永远不要将一个类硬编码为单例。这使得单例在应用程序代码中非常罕见并且通常是不必要的。在使用像 Spring 这样的 DI 框架时尤其如此。

                  单例在框架中确实可以用作“入口点”,但规则是将它们用作“根单例”(在依赖层次结构的开头)并让其余代码依赖于该单例尽可能少。

                  【讨论】:

                    猜你喜欢
                    • 2015-08-30
                    • 2017-05-08
                    • 2020-12-05
                    • 2012-08-02
                    • 2011-12-25
                    • 2017-09-28
                    • 2011-03-17
                    • 1970-01-01
                    相关资源
                    最近更新 更多