【问题标题】:Singleton code excerpt, an interview-question单例代码摘录,一个面试问题
【发布时间】:2009-06-17 22:53:04
【问题描述】:

我还有另一个面试问题。我认为这很愚蠢,但也许我缺少一些东西。问题询问这是哪种 GoF 模式(答案:单例),如果有任何问题,我如何解决。

我没有发现任何问题。我提到这永远不会被释放,我希望从这种模式中得到释放。这就是我所说的。我错过了什么吗?

public class Class1
{
    private static Class1 oInstance = null;
    private Class1() { }
    public static Class1 GetInstance()
    {
        if (oInstance == null)
        {
            oInstance  = new Class1();
        }
        return oInstance ;
    }
}

【问题讨论】:

    标签: c# design-patterns


    【解决方案1】:

    线程安全 - 如果从竞争线程中调用 GetInstance(),则可以创建多个实例。

    【讨论】:

      【解决方案2】:

      见:An obvious singleton implementation for .NET?

      在实现单例模式时,您需要考虑多个问题。

      • 多个调用者多个线程请求单例时会发生什么。它应该可以工作。
      • 何时调用单例实例构造函数。您可能希望推迟它,以便它在第一次调用请求单例时发生,您可能希望它在其他时间首先实例化。
      • 人们应该能够继承你的单例类吗?行为应该是什么?
      • 在单例实例化后,是否可以将您的单例实例切换到不同的实例。对此回答是违反了单例模式,因此通常包含单例的字段应该是readonly
      • API 设计,您应该使用属性 还是方法 来返回Singleton 实例。
      • 有些人说单身人士是邪恶的。您是否应该首先考虑它。这已经被经常讨论,一个好的起点是http://blogs.msdn.com/scottdensmore/archive/2004/05/25/140827.aspx

      以下是您可以遵循的良好通用模式。它的线程安全、密封、使用属性和延迟实例化单例。

      public sealed class Singleton
      {
          static class SingletonCreator
          {
              // This may seem odd: read about this at: http://www.yoda.arachsys.com/csharp/beforefieldinit.html
              static SingletonCreator() {}
              internal static readonly Singleton Instance = new Singleton();
          }
      
          public static Singleton Instance
          {
              get { return SingletonCreator.Instance; }
          }
      }
      

      【讨论】:

        【解决方案3】:

        其他人提到线程安全。还有一个事实是他们忘记将其标记为sealed,因此您可以从它继承并以这种方式创建多个实例。

        【讨论】:

        • 私有默认构造函数不阻止子类化吗?
        【解决方案4】:

        您在多线程代码中存在潜在的竞争条件。在另一个线程的构造函数完成之前,两个线程都可以通过 null 检查,因此两个线程都可以最终构造类。

        【讨论】:

          【解决方案5】:

          代码不是线程安全的。要做到这一点,您需要这样做:

          public class Class1
          {
              private static Class1 oInstance = null;
              private Class1() { }
              public static Class1 GetInstance()
              {
                  if (oInstance == null)
                  {
                      lock(typeof(Class1))
                      {
                          if (oInstance == null)
                          {
                              oInstance = new Class1();
                          }
                      }
                  }
                  return oInstance ;
              }
          }
          

          这是延迟加载实例的最有效方式,因为它只会在怀疑实例不会为下一次调用实例化时才会费心去锁定(可能会很昂贵)。在锁中再次检查确保它只会被实例化一次。

          【讨论】:

          • +1 ...尽管我个人不会使用 typeof(Class1) 进行锁定,而只是一个不用于其他任何事情的对象实例。
          • 我完全支持 Fredrik Mörk - 锁定类型对象是一种非常糟糕的做法(就像锁定它一样)。如果您锁定类型对象,每个代码都可以死锁您(甚至跨应用程序域)(如果您锁定它,每个有权访问实例的代码都可以死锁您)。锁定(typeof(Class1)){ Class1.GetInstance(); } 而你遇到了严重的麻烦......
          • 加里,看看我的答案中的模式,恕我直言,它的方式更干净
          • 有趣的是,我在 MSDN 上查找了建议,因为 lock() 不是我经常使用的东西,而在静态方法中使用 typeof() 是推荐的用法msdn.microsoft.com/en-us/library/aa664735(VS.71).aspx
          【解决方案6】:

          如果您有一个多线程应用程序,这可能会导致问题。如果两个线程同时请求,这可能会导致构造多个实例。

          我会在Singletons in C# 上查看此页面。它详细显示了问题以及更好的选择。

          【讨论】:

            【解决方案7】:

            那么解决方法如下?

            public class Class1
            {
                private static Class1 oInstance = new Class1();
                private Class1() { }
                public static Class1 GetInstance()
                {
                    return oInstance ;
                }
            }
            

            【讨论】:

            • 这很好,但至少 oInstance 应该是只读的,它不会延迟加载单例 ...
            【解决方案8】:

            不要在那家公司工作。单例模式不是一种经常使用的模式,它在纯 OO 系统中的适用性值得怀疑。如果您需要将单例模式恢复为正常构造的对象,那么撤消单例模式是一个大问题。

            【讨论】:

            • 这是一个非常广泛的声明。我认为这取决于您所做的开发类型。我的团队用 C++ 和 Java 编写系统软件,并且在这两种语言中都大量使用 Singletons。
            • 这是一个笼统的说法,但是,总的来说,这些天我喜欢将我所有的依赖项放在一个管理所有这些依赖项的内核中,而不是让我的所有依赖项分散在我的应用程序中。拥有单例会使测试变得更加困难。
            • 我认为这也可能是真的,直到我意识到它们在我当前的项目中非常有用......基本上它是一个实例的问题,有时你真的只想要你的对象的一个​​实例而没有更多。
            • 单例范式需要考虑的其他事项是可以通过启动另一个执行上下文来绕过它们。在学术方面,单例实例打破了软件的面向对象性。它是从一个类中创建一个对象,类和对象显然不是一回事。静态类、静态成员、静态变量和单例的情况类似于全局变量。以面向对象的方式确保您的整个程序使用相同的实例的学术“正确”方式是将其传递给构造函数。务实地说,这需要权衡。
            【解决方案9】:

            缺少线程安全,this page 解释得很好。

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2011-05-14
              • 2010-11-03
              • 1970-01-01
              • 2021-12-24
              • 2018-08-25
              • 1970-01-01
              • 2016-03-23
              相关资源
              最近更新 更多