單件模式(Singleton Pattern)

概述
    Singleton模式要求一個類有且僅有一個實例,並且提供了一個全局的訪問點。這就提出了一個問題:如何繞過常規的構造器,提供一種機制來保證一個類只有一個實例?客戶程序在調用某一個類時,它是不會考慮這個類是否只能有一個實例等問題的,所以,這應該是類設計者的責任,而不是類使用者的責任。 從另一個角度來說,Singleton模式其實也是一種職責型模式。因爲我們創建了一個對象,這個對象扮演了獨一無二的角色,在這個單獨的對象實例中,它集中了它所屬類的所有權力,同時它也肩負了行使這種權力的職責!
意圖
    保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。

1.簡單實現

/// <summary>
    /// 第一種:簡單實現
    /// </summary>
    public sealed class Singleton1
    {
        static Singleton1 instance = null;

        Singleton1()
        { }

        #region 第一種:簡單實現
        public static Singleton1 Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new Singleton1();
                }
                return instance;
            }
        }
        //這種方式的實現對於線程來說並不是安全的,因爲在多線程的環境下有可能得到Singleton類的多個實例。如果同時有兩個線程去判斷(instance == null),並
        //且得到的結果爲真,這時兩個線程都會創建類Singleton的實例,這樣就違背了Singleton模式的原則。實際上在上述代碼中,有可能在計算出表達式的值之前,
        //對象實例已經被創建,但是內存模型並不能保證對象實例在第二個線程創建之前被發現。 
        //該實現方式主要有兩個優點: 
        //1.由於實例是在 Instance 屬性方法內部創建的,因此類可以使用附加功能(例如,對子類進行實例化),即使它可能引入不想要的依賴性。 
        //2.直到對象要求產生一個實例才執行實例化;這種方法稱爲“惰性實例化”。惰性實例化避免了在應用程序啓動時實例化不必要的 singleton。
        #endregion
    }


 

2.安全的線程

/// <summary>
    /// 第二種:安全的線程
    /// </summary>
    public sealed class Singleton2
    {
        static Singleton2 instance = null;
        static readonly object padlock = new object();

        Singleton2()
        { 
        }

        #region 第二種:安全的線程
        public static Singleton2 Instance
        {
            get
            {
                lock (padlock)
                {
                    if (padlock == null)
                    {
                        instance = new Singleton2();
                    }
                }
                return instance;
            }
        }
        //這種方式的實現對於線程來說是安全的。我們首先創建了一個進程輔助對象,線程在進入時先對輔助對象加鎖然後再檢測對象是否被創建,
        //這樣可以確保只有一個實例被創建,因爲在同一個時刻加了鎖的那部分程序只有一個線程可以進入。這種情況下,對象實例由最先進入的那
        //個線程創建,後來的線程在進入時(instence == null)爲假,不會再去創建對象實例了。但是這種實現方式增加了額外的開銷,損失了性能。
        #endregion
    }


3.雙重鎖定

/// <summary>
    /// 第三種:雙重鎖定
    /// </summary>
    public sealed class Singleton3
    {
        static Singleton3 instance = null;
        static readonly object padlock = new object();

        Singleton3()
        { }

        #region 第三種:雙重鎖定
        public static Singleton3 Instance
        {
            get
            {
                if (instance == null)
                {
                    lock (padlock)
                    {
                        if (instance == null)
                        {
                            instance = new Singleton3();
                        }
                    }
                }
                return instance;
            }
        }
        //這種實現方式對多線程來說是安全的,同時線程不是每次都加鎖,只有判斷對象實例沒有被創建時它才加鎖,有了我們上面第一部分的裏面的分析,我們
        //知道,加鎖後還得再進行對象是否已被創建的判斷。它解決了線程併發問題,同時避免在每個 Instance 屬性方法的調用中都出現獨佔鎖定。它還允許您
        //將實例化延遲到第一次訪問對象時發生。實際上,應用程序很少需要這種類型的實現。大多數情況下我們會用靜態初始化。這種方式仍然有很多缺點:無
        //法實現延遲初始化。
        #endregion
    }


 

4.靜態初始化

/// <summary>
    /// 第四種:靜態初始化
    /// </summary>
    public sealed class Singleton4
    {
        static readonly Singleton4 instance = new Singleton4();

        static Singleton4()
        { }

        Singleton4()
        { }

        #region 第四種:靜態初始化
        #endregion
        public static Singleton4 Instance
        {
            get
            {
                return instance;
            }
        }
        //看到上面這段富有戲劇性的代碼,我們可能會產生懷疑,這還是Singleton模式嗎?在此實現中,將在第一次引用類的任何成員時創建實例。公共語言運行
        //庫負責處理變量初始化。該類標記爲 sealed 以阻止發生派生,而派生可能會增加實例。此外,變量標記爲 readonly,這意味着只能在靜態初始化期間(
        //此處顯示的示例)或在類構造函數中分配變量。 
        //該實現與前面的示例類似,不同之處在於它依賴公共語言運行庫來初始化變量。它仍然可以用來解決 Singleton 模式試圖解決的兩個基本問題:全局訪問
        //和實例化控制。公共靜態屬性爲訪問實例提供了一個全局訪問點。此外,由於構造函數是私有的,因此不能在類本身以外實例化 Singleton 類;因此,變
        //量引用的是可以在系統中存在的唯一的實例。 
        //由於 Singleton 實例被私有靜態成員變量引用,因此在類首次被對 Instance 屬性的調用所引用之前,不會發生實例化。 
        //這種方法唯一的潛在缺點是,您對實例化機制的控制權較少。在 Design Patterns 形式中,您能夠在實例化之前使用非默認的構造函數或執行其他任務。
        //由於在此解決方案中由 .NET Framework 負責執行初始化,因此您沒有這些選項。在大多數情況下,靜態初始化是在 .NET 中實現 Singleton 的首選方法。
    }


 

5.延遲初始化

/// <summary>
    /// 第五種:延遲初始化
    /// </summary>
    public sealed class Singleton5
    {
        Singleton5()
        { }

        public static Singleton5 Instance
        {
            get
            {
                return Nested.instance;
            }
        }

        class Nested
        {
            static Nested()
            {
            }

            internal static readonly Singleton5 instance = new Singleton5();
        }
    }
    //這裏,初始化工作有Nested類的一個靜態成員來完成,這樣就實現了延遲初始化,並具有很多的優勢,是值得推薦的一種實現方式。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章