記一下學習單例模式的筆記:
單例就是要保證該類僅有一個實體,實作完全封閉的單例(外部不能new)其實就要兩點要求:
- 全域訪問:需要一個該型別的全域靜態變數,每次獲取實體時都要判斷它是否null,不存在new,存在通過一個方法直接回傳該值獲取實體來保證物件唯一;
- 實體化控制:new實體不能外部new、造成實體不唯一,需要一個私有構造器禁用共有構造器,
根據new實體的時機,分為餓漢式和懶漢式:
一、 餓漢式單例:靜態變數初始化時new
特點:加載時new,一開始全域就存在該唯一實體,每次用到只要獲取就行,提前占用系統資源但不存在執行緒安全問題,代碼如下:
1 public sealed class Singleton 2 { 3 private static readonly Singleton instance = new Singleton(); 4 private Singleton() { } 5 6 public static Singleton GetInstance() 7 { 8 return instance; 9 } 10 }View Code
二、 懶漢式單例:需要該實體的時候再new
特點:真正需要用到的時候才實體化,不提前占用資源但多個執行緒同時用到該實體時,會存在判斷靜態變數都為null都去new而產生多個實體的情況,有執行緒安全問題,但可以用雙重鎖定解決,
單執行緒懶漢單例代碼如下:
1 public class Singleton 2 { 3 private static Singleton instance = null; 4 private Singleton() { } 5 6 public static Singleton GetInstance() 7 { 8 if (instance == null) 9 instance = new Singleton(); 10 return instance; 11 } 12 }View Code
多執行緒懶漢單例代碼如下:
1 public class Singleton 2 { 3 private static Singleton instance = null; 4 private static readonly object obj = new object(); 5 private Singleton() { } 6 7 public static Singleton GetInstance() 8 { 9 //雙重鎖定 10 if (instance == null)//只有為null需要實體化處理時才進行加鎖,提高性能避免不必要的等待 11 { 12 lock (obj) 13 { 14 if (instance == null)//避免其他執行緒等待鎖釋放期間有執行緒已經實體化,從而造成多個實體 15 instance = new Singleton(); 16 } 17 } 18 return instance; 19 } 20 }View Code
三、 注冊式單例
介紹一個有意思的單例-泛型注冊式,是對單例的擴展,主要了解它的設計思想和對泛型的運用,
其實每個類單例模式實作代碼都是差不多的:
- 相同的結構和方法:是否可以考慮進行抽象提取一個公共的呼叫介面?
- 方法的實作相同唯一不同是輸出型別:是否可以考慮設計一個適用于不同型別的通用處理方式?這個適用不同型別通用解決就要用到泛型,
實作代碼如下(例子使用餓漢式,當然也可以用懶漢式):
1 public abstract class Singleton<T> where T:class,new() 2 { 3 private static readonly T instance = new T(); 4 protected Singleton() { } 5 6 public static T GetSingleton()//獲取單例 7 { 8 return instance; 9 } 10 } 11 public class Person : Singleton<Person> { }View Code
可以看到這種單例通過繼承的方式,既可以new實體也可以獲取單例實體,如果要實作上面的完全封閉(禁用外部new),也可以完全在Person類中寫個私有構造器在Singleton<T>類中實體的獲取new T()改為反射呼叫私有構造器的方式實作,總感覺怪怪的,
下面是主程式呼叫該單例方法:
1 static void Main(string[] args) 2 { 3 Person p1 = Person.GetSingleton(); 4 Person p2 = Singleton<Person>.GetSingleton(); 5 6 if (object.ReferenceEquals(p1, p2)) 7 { 8 Console.WriteLine("兩個物件是同一實體"); 9 } 10 Console.ReadKey(); 11 } 12View Code
輸出結果:

轉載請註明出處,本文鏈接:https://www.uj5u.com/ruanti/251607.html
標籤:設計模式
