簡體   English   中英

靜態構造函數-C#中的Singleton設計模式

[英]Static constructor - Singleton Design pattern in c#

如果我在單例設計模式中將私有構造函數替換為靜態構造函數怎么辦?

public sealed class Singleton
{
    private static Singleton instance=null;

    private Singleton()
    {
    }

    public static Singleton Instance
    {
        get
        {
            if (instance==null)
            {
                instance = new Singleton();
            }
            return instance;
        }
    }
}

靜態構造函數將僅被調用一次,我在實現中找不到任何區別。 我們可以用靜態構造函數代替private嗎?

在這種情況下,私有構造函數所做的全部工作就是防止類之外的任何實例實例化Singleton類的實例,這幾乎可以肯定是有意的,因為Singleton僅應具有單個實例。

靜態類構造函數在使用該類型或其任何靜態成員之前,會在未知時間針對該類型運行一次。 在運行靜態構造函數之前,將初始化靜態字段。

因此,我想您可以用一個靜態的構造函數替換該構造函數,但這將為您提供Singleton Type上隱式的無參數構造函數,該構造函數將允許任何人實例化一個實例,這可能與您使用的原因不符。首先是單例模式。 實際上,它也不會改變類的構造方式,為什么呢?

例如,以以下類為例:

public class Test { }

在幕后,由於沒有聲明的構造函數,因此C#編譯器向類隱式添加了無參數的公共構造函數,從而允許使用者創建實例。

public class Program {
    public static void Main() { 
        var test = new Test();
    }
}

如果您希望能夠創建類的實例,那么這一切都很好。 單例模式旨在僅向使用者提供類型的單個實例。 我們可以像這樣將這個靜態實例添加到我們的測試類型中:

public class Test { public static Test Instance {get;} = new Test(); }

並且我們將能夠像下面這樣獲得這個靜態實例:

public class Program {
    public static void Main() {
        var test = Test.Instance; // good
        var other = new Test(); // less than ideal
    }
}

因此,正如預期的那樣,我們正在通過其實例字段提供對單例對象的訪問,但是我們仍然可以創建單例類型的實例,這種情況不太好,因為它違反了單例的目的(即,只有一個共享對象實例。)

因此,我們向該類型添加了一個私有的,無參數的構造函數。

public class Test { 
    private Test() {}
    public static Test Instance {get;} = new Test(); 
}

向類型添加構造函數將導致C#編譯器不添加隱式的公共參數少構造函數。 將其設置為私有允許在類范圍內對其進行訪問,該范圍用於實例化我們的實例屬性,並防止其他任何事情實例化該對象。 最終結果是:

public class Program {
    public static void Main() {
        var test = Test.Instance; // good
        var other = new Test(); // Compile time error
    }
}

現在,您的單例對象可以防止實例化該類的其他實例,並且使用它的唯一方法是通過預期的instance屬性。

簡單來說,如果刪除私有構造函數,那么任何人都可以創建Singleton的新實例:

// With the private constructor, the compiler will prevent this code from working.
// Without it, the code becomes legal.
var newInstance = new Singleton();

而且,如果任何人都可以如上所述實例化Singleton ,那么您將不再擁有Singleton。

另一種更清潔的方法是在私有實例上使用readonly

這是更少的代碼,並且也是線程安全的。 CLR為您處理所有事情,不需要lock ,檢查null和其他東西。

public sealed class Singleton
{
    private static readonly Singleton _instance = new Singleton();

    public static Singleton Instance {
        get {
                return _instance;
            }            
    }

    private Singleton()
    {
    }
}

然后只需測試:

[TestMethod]
public void IsSingleton()
{
    Assert.AreSame(Singleton.Instance, Singleton.Instance);
}

編輯:

使用lock示例

public sealed class Singleton
{
    private static readonly object _lock = new object();
    private static Singleton instance = new Singleton();

    public static Singleton Instance
    {
        get
        {
            lock(_lock)
            {
                if (instance==null)
                {
                    instance = new Singleton();
                }
                return instance;    
            }
        }
    }

    private Singleton()
    {
    }
}

簡單來說,如果刪除private ,則默認的public構造函數將公開。 然后,局外人將被允許使用new Singleton(); 並增加Singleton類的實例數量。 因此,將沒有Singleton模式。

此外,這種經典的Singleton模式實現(private constructor + static getInstance() with either lazy-loading or eager loading)非常邪惡 在現代,您必須改用Dependency-Injection框架。

這應該很好。 您還可以將類設為靜態和泛型,以便可以在instance存儲想要保留的任何類型的值。 這將有利於關注點的分離,保持單例模式及其包含的類是分離的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM