一、基本概述 單件模式:確保一個類只有一個實例,並提供一個全局訪問點。 解析如下: 1)首先,該Singleton的構造函數必須是私有的,以保證客戶程式不會通過new()操作產生一個實例,達到實現單例的目的; 2)因為靜態變數的生命周期跟整個應用程式的生命周期是一樣的,所以可以定義一個私有的靜態全局 ...
一、基本概述
單件模式:確保一個類只有一個實例,並提供一個全局訪問點。
解析如下:
1)首先,該Singleton的構造函數必須是私有的,以保證客戶程式不會通過new()操作產生一個實例,達到實現單例的目的;
2)因為靜態變數的生命周期跟整個應用程式的生命周期是一樣的,所以可以定義一個私有的靜態全局變數uniqueInstance來保存該類的唯一實例;
3)必須提供一個全局函數訪問獲得該實例。
如下圖結構說明圖:
二、詳細說明
單件模式的創建,有三種方式。
- 使用經典方式,存在一個問題,當有多個線程同時訪問時,會創建多個實例,違反了單件的本意。
- 使用急切方式,如果應用程式總是創建並使用單件實例,或者在創建和運行時方面的負擔不太繁重,該方式可以使用。它的初始化交由靜態構造函數實現,並可以在運行時編譯。在這種模式下,無需自己解決線程安全性問題,CLR會給我們解決。由此可以看到這個類被載入時,會自動實例化這個類,而不用在第一次調用GetInstance()後才實例化出唯一的單例對象。
- 使用懶惰(雙重檢查加鎖)方式,首先檢查是否實例已經創建,如果尚未創建,“才”進行同步。這樣一來,只有第一次會同步,同步中會再檢查是否實例已經創建。如果性能是你關心的重點,那麼這個做法可以幫你大大地減少GetInstance()的時間耗費。
問:難道我不能創建一個類,把所有的方法和變數都定義為靜態的,把類直接當作一個單件?
答:如果你的類自給自足,而且不依賴於複雜的初始化,那麼你可以這麼做。但是,因為靜態初始化的控制權是在CLR手上,這麼做有可能導致混亂,特別是當有許多類牽涉其中的時候。這麼做常常會造成一些微妙的、不容易發現的和初始化的次序有關的bug。除非你有絕對的必要使用類的單件,否則還是建議使用對象的單件,比較保險。
問:我還是不瞭解為何全局變數比單件模式差。
答:在.Net中,全局變數基本上就是對對象的靜態引用。在這樣的情況下使用全局變數會有一些缺點,我們已經提到了其中的一個,急切實例化VS延遲實例化。但是我們要記住這個模式的目的,確保類只有一個實例並提供全局訪問。全局變數可以提供全局訪問,但是不能確保只有一個實例。
三、代碼列表
public class Singleton { //其他有用的單件數據 private Singleton() { } //方式一:經典方式 /*private static Singleton uniqueInstance; public static Singleton GetInstance() { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } return uniqueInstance; }*/ //方式二:急切方式 /*private static Singleton uniqueInstance = new Singleton(); public static Singleton GetInstance() { return uniqueInstance; }*/ //方式三:雙重檢查加鎖方式 /*private static Singleton uniqueInstance; public static Singleton GetInstance() { if (uniqueInstance == null) { lock (uniqueInstance) { if (uniqueInstance == null) { uniqueInstance = new Singleton(); } } } return uniqueInstance; //Interlocked類為多個線程共用的變數提供原子操作。 //CompareExchange方法比較兩個對象是否相等,如果相等,則替換其中一個對象。 //return Interlocked.CompareExchange(ref uniqueInstance, new Singleton(), null); }*/ //其他有用的單件方法 }View Code
---------------------------------以上內容根據《Head First 設計模式》進行整理