建立型模式 --- 單件模式(Singleton Pattern)

Black-Coder發表於2016-03-06

動機(Motivation):
在軟體系統中,經常有這樣一些特殊的類,必須保證它們在系統中只存在一個例項,才能確保它們的邏輯正確性、以及良好的效率。
如何繞過常規的構造器,提供一種機制來保證一個類只建立一個例項?
這應該是類設計者的責任,而不是類使用者的責任。
結構圖:
這裡寫圖片描述
意圖:
保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。
生活的例子:
這裡寫圖片描述

適用性:
(1)當類只能有一個例項而且客戶可以從一個眾所周知的訪問點訪問它時。
(2)當這個唯一例項應該是通過子類化可擴充套件的,並且客戶應該無需更改程式碼就能使用一個擴充套件的例項時。

程式碼實現:
(1)單執行緒Singleton實現

class SingleThread_Singleton
    {
        private static SingleThread_Singleton instance = null;
        private  SingleThread_Singleton(){}
        public static SingleThread_Singleton Instance
        {
            get
            {
                if (instance == null)
                {
                    instance = new SingleThread_Singleton();
                }
                return instance;
            }
        }
    }

以上程式碼在單執行緒情況下不會出現任何問題。但是在多執行緒的情況下卻不是安全的。
如兩個執行緒同時執行到 if (instance == null)判斷是否被例項化,一個執行緒判斷為True後,在進行建立
instance = new SingleThread_Singleton();之前,另一個執行緒也判斷(instance == null),結果也為True.
這樣就就違背了Singleton模式的原則(保證一個類僅有一個例項)。
怎樣在多執行緒情況下實現Singleton?
(2)多執行緒Singleton實現:

class MultiThread_Singleton
      {
       private  static volatile MultiThread_Singleton instance = null;
       private static object lockHelper = new object();
       private MultiThread_Singleton() { }
       public static MultiThread_Singleton Instance
       {
           get
           {
               if (instance == null)
               {
                   lock (lockHelper)
                   {
                     if (instance == null)
                     {
                           instance = new MultiThread_Singleton();
                     }
                   }
               }
               return instance;
           }         
       }

此程式對多執行緒是安全的,使用了一個輔助物件lockHelper,保證只有一個執行緒建立例項(如果instance為空,保證只有一個執行緒instance = new MultiThread_Singleton();建立唯一的一個例項)。(Double Check)
請注意一個關鍵字volatile,如果去掉這個關鍵字,還是有可能發生執行緒不是安全的。
volatile 保證嚴格意義的多執行緒編譯器在程式碼編譯時對指令不進行微調。

(3)靜態Singleton實現

class Static_Singleton
        {
             public static readonly Static_Singleton instance = new Static_Singleton();
             private Static_Singleton() { }
         }

以上程式碼展開等同於

class Static_Singleton
{
    public static readonly Static_Singleton instance;
    static Static_Singleton()
    {
        instance = new Static_Singleton();
    }
    private Static_Singleton() { }
}

由此可以看出,完全符合Singleton的原則。
優點: 簡潔,易懂
缺點: 不可以實現帶引數例項的建立。

相關文章