設計模式(建立型模式)——單例模式

1.定義編程

保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。安全

 

2.適用性多線程

1)當類只能有一個實例而客戶能夠從一個衆所周知的訪問點訪問它時。併發

2)當這個惟一實例應該是經過子類化可擴展的,而且客戶應該無需更改代碼就能使用一個擴展的實例時。ide

 

3.結構性能

 

1 單例模式類圖spa

注:線程

Singleton:定義一個Instance操做,容許客戶訪問它的惟一實例。Instance是一個類操做(C#中爲靜態方法),Singleton負責建立它本身的惟一實例。3d

4.實現方法code

1)經典模式

靜態變量uniqueInstance存儲惟一實例。公有靜態方法GetInstance提供訪問SingletonFirst的全局訪問點,因爲除了GetInstance方法外,類的成員均爲私有的,因此GetInstance提供的爲惟一訪問方式。在GetInstance()方法中,對uniqueInstance是否爲null作了判斷,所以使得對象只能被實例化一次。

 1 public class SingletonFirst
 2 {
 3       private static SingletonFirst uniqueInstance;
 4       private SingletonFirst() { }
 5 
 6       public static SingletonFirst GetInstance()
 7       {
 8           if(uniqueInstance==null)
 9           {
10               uniqueInstance = new SingletonFirst();
11           }
12           return uniqueInstance;
13       }
14 }

2)使用屬性而不是方法

這種實現方式與第一種方式的區別在於客戶經過屬性得到對象實例。

 

 1 public class SingletonSecond
 2 {
 3     private static SingletonSecond uniqueInstance;
 4     private SingletonSecond() { }
 5     public static SingletonSecond Instance
 6     {
 7         get
 8         {
 9             if (uniqueInstance == null)
10             {
11                 uniqueInstance = new SingletonSecond();
12             }
13             return uniqueInstance;
14         }
15     }
16 }

 

3)只能得到一次單例

這種單例模式的實現方式較以前幾種有較大的差異客戶不能反覆調用Instance屬性得到實例;客戶要將第一次得到的實例賦給一個變量,以後若要訪問實例,則只能經過使用這一變量的間接方式。

 1 public class SingletonThird
 2 {
 3     private static bool instanceFlag = false;
 4     private SingletonThird() { }
 5 
 6     public static SingletonThird Instance
 7     {
 8         get 
 9         {
10             if (!instanceFlag)
11             {
12                 return new SingletonThird();
13             }
14             else
15             {
16                 return null;
17             }
18         }
19     }
20 }

4)支持併發訪問

這種單例模式的實現方式與第一種基本一致,只不過在聲明uniqueInstanc的同時完成對象的實例化。優勢是靜態字段在類首次被使用前初始化,能夠防止併發訪問。

 1 public class SingletonFourth
 2 {
 3         private static readonly SingletonFourth uniqueInstance = new    SingletonFourth();
 4         private SingletonFourth() { }
 5 
 6         public static SingletonFourth GetInstance()
 7         {
 8             return uniqueInstance;
 9         }
10 }

5)使用私有靜態構造器

這種方式使用了私有的靜態構造器。靜態構造器在類第一次被訪問前由CLR自動調用,達到防止併發訪問的目的。使用靜態構造器而不是靜態初始化器的好處是:能夠在靜態構造器中處理異常。

 1 public class SingletonFifth
 2 {
 3         private static readonly SingletonFifth uniqueInstance;
 4         static SingletonFifth() 
 5         {
 6             uniqueInstance = new SingletonFifth();
 7         }
 8 
 9         public static SingletonFifth GetInstance()
10         {
11             return uniqueInstance;
12         }
13 }

6)使用鎖

這種方式採用加鎖的辦法來防止併發訪問缺點就是鎖的開銷比較大,若是用戶對於性能比較關心,那麼不建議採用這種方式。也能夠考慮其餘開銷比較小的同步機制。

 

 1 public class SingletonSixth
 2 {
 3         private static SingletonSixth uniqueInstance;
 4         private static Object lockObj = new object();
 5         private SingletonSixth() { }
 6 
 7         public static SingletonSixth GetInstance()
 8         {
 9             lock (lockObj)
10             {
11                 if (uniqueInstance == null)
12                 {
13                     uniqueInstance = new SingletonSixth();
14                 }
15                 return uniqueInstance;
16             }
17         }
18 }

 

7)延遲初始化

使用Lazy<T>達到延遲初始化的目的,但這種方式是非線程安全的。

 1 public class SingletonSeventh
 2 {
 3         private static readonly Lazy<SingletonSeventh> lazy =
 4             new Lazy<SingletonSeventh>(() => new SingletonSeventh());
 5         private SingletonSeventh(){}
 6        
 7         public static SingletonSeventh Instance 
 8         {
 9             get
10             {
11                 return lazy.Value;
12             }
13         }
14 }

8)最簡潔的方式

這種方法與標準的單例模式結構不符,但這種方式的確實現了單例模式   符合單例模式的定義:只有一個實例且提供一個全局訪問點uniqueInstance靜態變量在聲明時初始化,同時構造器可訪問性爲private,確保類不容許在外部實例化uniqueInstance變量的可訪問性爲public,因此全局的訪問點就是uniqueInstance

 

1 public class SingletonEighth
2 {
3         public static readonly SingletonEighth uniqueInstance = new SingletonEighth();
4         private SingletonEighth()
5         {
6             //這裏執行初始化工做或其餘任務
7         }
8 }

 

5.擴展單例模式使能夠有幾個實例

 1 public class SingletonExpansion
 2 {
 3         private static int count = 0;
 4         private static SingletonExpansion uniqueInstance;
 5         private SingletonExpansion(){}
 6 
 7         public static SingletonExpansion Instance
 8         {
 9             get
10             {
11                 if (count < 2)
12                 {
13                     uniqueInstance = new SingletonExpansion();
14                     count++;
15                     return uniqueInstance;
16                 }
17                 else
18                 {
19                     return uniqueInstance;
20                 }
21             }
22         }
23 }

6 概念辨析

1)使用靜態成員與使用單例模式之間的比較:

相同點:

  • 使用靜態成員與使用單例模式均可以得到類的惟一實例。
  • 使用靜態成員與使用單例模式均可以將數據一次性地加載到內存中,已提升系統運行效率。

不一樣點:

  • 使用單例模式而不使用靜態成員可能會增長代碼的複雜度。
  • 單例模式提供了更多的控制機制。能夠在構造器中處理數據或執行其餘操做;能夠控制類的狀態,根據類的狀態完成適當的操做。
  • 在單例模式中運用接口,使得用戶能夠擴展程序而不比修改代碼,這也符合開放封閉原則(OCP)。

2)一個類只有惟一的實例不必定就運用了單例模式

單例模式的兩個要素:

  • 有且僅有一個實例。
  • 必須提供一個全局的訪問點。

上述兩個條件缺一不可,不然就不是單例模式。

 

7 實現方式總結

1)實現了延遲初始化的爲:SingletonFirst,SingletonSecond,SingletonThird,SingletonSeventh

    延遲初始化的好處:若對象佔用資源(時間上建立時間比較長或空間上耗費內存較大)比較大,程序的執行過程當中從未使用到,那麼延遲初始化能夠避免耗費資源。若是對象並不佔用較多的資源那麼採用哪一種方式都無所謂了。

2)線程安全的:SingletonFourth,SingletonFifth,SingletonSixth

多線程編程中其餘幾種實現方法可能會多個實例。

 

8 .NET Framework 中的單例模式

1) Microsoft.SqlServer.Server.SmiContextFactory

此方法實現方式與SingletonEighth的實現方式相同

源碼概要

 1 namespace Microsoft.SqlServer.Server {
 2 
 3 using System;
 4     
 5 using System.Data.Common;
 6     
 7 using System.Data.SqlClient;
 8     
 9 using System.Diagnostics;
10 
11 sealed internal class SmiContextFactory 
12  {
13         
14     public static readonly SmiContextFactory Instance = new SmiContextFactory();
15     //省略一些變量
16     private SmiContextFactory() {
17 
18     //省略了具體實現}
19 
20     //省略其餘方法
21 
22     }
23 }

2) sealed internal class SqlConnectionFactory

此方法實現方式與SingletonEighth的實現方式相同 

源碼概要

 

 1 namespace System.Data.SqlClient
 2 {
 3     
 4 using System;
 5     
 6 using System.Data.Common;
 7     
 8 //省略其餘using 
 9     
10 using Microsoft.SqlServer.Server;
11 sealed internal class SqlConnectionFactory : DbConnectionFactory {
12                 private SqlConnectionFactory() :
13 base(SqlPerformanceCounters.SingletonInstance) {}
14 
15 public static readonly SqlConnectionFactory SingletonInstance =         new SqlConnectionFactory();
16 //省略如下其餘代碼
17 }

 

3) sealed internal class SqlPerformanceCounters

此方法實現方式與SingletonEighth的實現方式相同

源碼概要

 

 1 namespace System.Data.SqlClient
 2 {
 3     
 4 using System;
 5     
 6 using System.Data.Common;
 7     
 8 //省略其餘using語句 
 9     
10 using Microsoft.SqlServer.Server;
11 
12 sealed internal class SqlPerformanceCounters :
13 DbConnectionPoolCounters {
14         
15 private const string CategoryName = ".NET Data Provider for         SqlServer";
16  
17 private const string CategoryHelp = "Counters for                     System.Data.SqlClient";
18  
19         
20 public static readonly SqlPerformanceCounters SingletonInstance         = new SqlPerformanceCounters();
21  
22                 [System.Diagnostics.PerformanceCounterPermissionAttribute
23 (System.Security.Permissions.SecurityAction.Assert,         PermissionAccess=PerformanceCounterPermissionAccess.Write,         MachineName=".", CategoryName=CategoryName)]
24         
25 private SqlPerformanceCounters() : base (CategoryName, CategoryHelp) {
26         }
27    
28 }
29 }
相關文章
相關標籤/搜索