【问题标题】:What is the use of null checking in Singleton pattern?单例模式中的空检查有什么用?
【发布时间】:2015-12-13 08:38:08
【问题描述】:

在单例模式中,我们有一个私有构造函数和一个公共静态方法,如下所示 -

public class MyClass
{
     private static MyClass _uniqueInstance;

     private MyClass()
     { 
     }

     public static MyClass GetInstance()
     {
         if(_uniqueInstance==null)
         { 
             _uniqueInstance = new MyClass();
         }
         return _uniqueInstance;
     }
}

我们可以通过调用静态方法来创建这个类的一个和唯一一个实例,只要我们需要这个类的对象,比如 -

var myObject = MyClass.GetInstance();

但我很困惑为什么我们在 GetInstance() 方法中检查 null,因为“_uniqueInstance”已经是一个静态变量,所以它只会被初始化并分配一次内存。即使我们不检查 null 并且仍然使用“new”初始化对象,也不会为该对象再次分配内存,因为它是一个静态变量。那么,这个空检查有什么用呢? 请消除我的疑问。

【问题讨论】:

标签: c# design-patterns singleton


【解决方案1】:

我感觉初始化器、工厂和单例之间存在混淆。

字段初始化器:

static readonly object Value = new object();

工厂方法:

static object CreateValue()
{
    return new object();
}

单例模式:

static object _value;

static object Value
{
    get
    {
        return _value ?? (_value = new object());
    }
}

初始化器在编译时被删除到static constructor,它会像你猜到的那样运行一次。除了顺序,静态字段的初始化是不可控的。当任何静态字段初始化时,所有静态字段都会初始化。单例模式可以防止这种情况发生。

工厂方法旨在作为instance constructor 的抽象。

单例模式可以被认为是字段初始化器的抽象,确保在必要时才引入资源。但是,对于最肯定引用的资源,例如 String.Empty,最好使用静态字段来避免混乱。

【讨论】:

    【解决方案2】:

    如果你使用以下代码:

    public static MyClass GetInstance()
    {
        _uniqueInstance = new MyClass();
        return _uniqueInstance;
    }
    

    那么每次有人调用这个GetInstance 你都会得到一个不同的类实例,这与单例是矛盾的。单例模式的想法是始终获得相同的类实例,无论您在应用程序中调用它多少次。而且这个实例应该只被构造一次。

    所以基本上 null 检查只会在第一次调用 GetInstance 以实例化私有静态字段(默认为 null)时返回 true,并且在后续调用中将返回相同的实例。

    请记住,您在此处展示的这种单例模式实现不是线程安全的。如果 2 个线程在开始时同时调用 GetInstance 方法,可能会得到 2 个不同的实例。

    您可以在this article 中阅读有关单例模式和各种 C# 实现的更多信息。

    【讨论】:

      【解决方案3】:

      我们使用单例模式只获取一个对象的一个​​实例,并在任何地方使用这个实例。

      如果我们删除空检查if(_uniqueInstance==null),那么每次调用GetInstance 时都会创建一个新实例并将其存储在_uniqueInstance 变量中。

      即使我们不检查 null 并且仍然使用 “new”,不会再为这个对象分配内存,因为它是一个 静态变量。

      内存仅作为引用类型分配给_uniqueInstance,因为它是静态的。但是您可以为这个静态变量分配许多引用,并且可以根据需要在内存中多次创建这些对象。

      那么,这个空检查有什么用

      空检查确保_uniqueInstance 只分配一次MyClass 的实例,并且在应用程序域的整个生命周期内永远不会更改。所以每次调用GetInstance 都会得到相同的MyClass 实例。

      Read more about singleton

      【讨论】:

        【解决方案4】:

        这是错误的:

        即使我们不检查 null 并且仍然使用 “new”,不会再为这个对象分配内存,因为它是一个 静态变量。

        调用new 将分配新内存,_uniqueInstance 将有一个新指针。因此,每次调用该方法时都会有不同的实例 - 它不是单例。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2011-10-16
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2011-01-21
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多