NET設計模式-單例模式(Singleton Pattern)

1. 概述

Singleton Pattren 要求一個類有且僅有一個實例,並且提供一個全局變量。這個創建的對象是獨一無二的,在這個單獨對象實例中,集中所創建類的所有屬性和方法。
在創建一個單例,何時需要,這是程序設計的關鍵。從定義上可知這個類供全局調用,產品(程序)都可調用,所有是個全局靜態變量,一般是不允許有派生類的。比如,火車的票數及票種,必須全局變量,這個往往是爲了防止多線程調用時,導致問題溢出。

2. 模型圖及思路

實例圖

思路圖

3. 代碼實現

//單例模式類不能派生
public sealed class Singleton
{
    //靜態對象,才能在靜態函數中訪問
    private static Singleton uniqueInstance;

    //線程安全控制實例
    static object synobj = new object();
    public static Singleton GetInstace()
    {
         //不加線程控制時,當兩個線程同時運行GetInstance方法時,此時兩個線程判斷(uniqueInstance ==null)這個條件時都返回真,此時兩個線程就都會創建Singleton的實例
            // 當第一個線程運行到這裏時,此時會對locker對象 "加鎖",
            // 當第二個線程運行該方法時,首先檢測到locker對象爲"加鎖"狀態,該線程就會掛起等待第一個線程解鎖
            // lock語句運行完之後(即線程運行完之後)會對該對象"解鎖"
        lock(synobj)
        {
            // 如果類的實例不存在則創建,否則直接返回
             //爲創建實例時,進行創建
           if (uniqueInstance == null)
           {
                uniqueInstance = new Singleton();
           }
      }
        return uniqueInstance;
    }

    //私有構造函數,只允許在此類中創建對象
    private Singleton()
    {
    }

}

以上的設計確實解決多線程的問題,但是上面的代碼對於每個線程輔助對象locker枷鎖後,在判斷實例時候存在,對於這個操作完全沒必要。可以當地一個線程創建實例後,後面的線程只需要直接判斷是否爲null。就如一下的代碼。

//單例模式類不能派生
public sealed class Singleton
{
    //靜態對象,才能在靜態函數中訪問
    private static Singleton uniqueInstance;

    //線程安全控制實例
    static object synobj = new object();
    public static Singleton GetInstace()
    {
         //不加線程控制時,當兩個線程同時運行GetInstance方法時,此時兩個線程判斷(uniqueInstance ==null)這個條件時都返回真,此時兩個線程就都會創建Singleton的實例
            // 當第一個線程運行到這裏時,此時會對locker對象 "加鎖",
            // 當第二個線程運行該方法時,首先檢測到locker對象爲"加鎖"狀態,該線程就會掛起等待第一個線程解鎖
            // lock語句運行完之後(即線程運行完之後)會對該對象"解鎖" 
            //只需要家這句判斷就可以了
      if(uniqueInstance == null)
       {
        lock(synobj)
        {
            // 如果類的實例不存在則創建,否則直接返回
             //爲創建實例時,進行創建
           if (uniqueInstance == null)
           {
                uniqueInstance = new Singleton();
           }
      }
     }
        return uniqueInstance;
    }

    //私有構造函數,只允許在此類中創建對象
    private Singleton()
    {
    }

}
public sealed class Singleton
 2{
 3    static readonly Singleton instance=new Singleton();
 4
 5    static Singleton()
 6    {
 7    }
 8
 9    Singleton()
10    {
11    }
12
13    public static Singleton Instance
14    {
15        get
16        {
17            return instance;
18        }
19    }
20 }
21

看到上面這段富有戲劇性的代碼,我們可能會產生懷疑,這還是Singleton模式嗎?在此實現中,將在第一次引用類的任何成員時創建實例。公共語言運行庫負責處理變量初始化。該類標記爲 sealed 以阻止發生派生,而派生可能會增加實例。此外,變量標記爲 readonly,這意味着只能在靜態初始化期間(此處顯示的示例)或在類構造函數中分配變量。

該實現與前面的示例類似,不同之處在於它依賴公共語言運行庫來初始化變量。它仍然可以用來解決 Singleton 模式試圖解決的兩個基本問題:全局訪問和實例化控制。公共靜態屬性爲訪問實例提供了一個全局訪問點。此外,由於構造函數是私有的,因此不能在類本身以外實例化 Singleton 類;因此,變量引用的是可以在系統中存在的唯一的實例。
由於 Singleton 實例被私有靜態成員變量引用,因此在類首次被對 Instance 屬性的調用所引用之前,不會發生實例化。

4.要點知識

  1. Singleton模式是限制而不是創建。
  2. Singleton類中實例可以設置爲Protected供子類派生
  3. Singleton考慮了對象創建的管理,沒有進行銷燬,就支持垃圾回收的平臺,就不用對銷燬進行管理。
  4. 優點:阻止其他對象實例化自己的副本,保證所有對象訪問的唯一實例。
  5. 缺點:使用Singleton模式時,開發人員不能有new,進行實例化。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章