C#設計模式——單例模式
一、單例模式定義:
確保一個類只有一個實例,並提供一個訪問它的全局訪問點。
二、背景:
當我們的系統中某個對象只需要一個實例的情況,例如:操作系統中只能有一個任務管理器,操作文件時,同一時間內只允許一個實例對其操作等。
三、實現思維:
1、私有化構造函數,使外界不能創建該類實例。
2、聲明一個靜態變量接收類的實例。
3、定義一個靜態共有方法提供全局訪問。
四、相關代碼:
1、簡單例子:
眾所周知,我們添加一個按鈕事件show出另外一個窗體,一般的做法是new一個窗體對象然後去show,但是每點擊一次都會show多出一個新窗體。那怎麽樣才能做到點擊一個show出一個窗體之後只要新窗體不關閉,不管我們再怎麽點擊也不會show多新窗體呢?這裏就是用到單例模式了,相關代碼如下:
public partial class Form2 : Form { //定義一個靜態變量來保存類的實例 public static Form2 FrmSingle = null; //私有化構造函數,使外界不能創建該類實例 private Form2() { InitializeComponent(); } /// <summary> /// 定義靜態公有方法提供全局訪問 /// </summary> ///<returns></returns> public static Form2 GetSingle() { // 如果類的實例不存在則創建,否則直接返回 if (FrmSingle == null) { FrmSingle = new Form2(); } return FrmSingle; } }
public partial class Form1 : Form {public Form1() { InitializeComponent(); } private void button1_Click(object sender, EventArgs e) { //調用窗體2靜態方法實現單例模式 Form2 frm = Form2.GetSingle(); frm.Show(); } }
通過上面的簡單例子,相信大家也覺得單例模式並不難,但是上面的單例模式的實現是單線程的,然而在多線程的情況下會得到多個Form2實例,因為在兩個線程同時運行GetSingle方法時,此時兩個線程判斷(FrmSingle ==null)這個條件時都返回真,此時兩個線程就都會創建Form2的實例,這樣就違背了我們單例模式初衷了,解決方法也很簡單,使GetSingle方法在同一時間只運行一個線程運行就好了。
//定義一個靜態變量來保存類的實例 public static Form2 FrmSingle = null; //定義一個標識確保線程同步 public static readonly object locker = new object(); //私有化構造函數,使外界不能創建該類實例 private Form2() { InitializeComponent(); } /// <summary> /// 定義公有方法提供全局訪問 /// </summary> /// <returns></returns> public static Form2 GetSingle() { if (FrmSingle == null) { lock (locker) { // 如果類的實例不存在則創建,否則直接返回 if (FrmSingle == null) { FrmSingle = new Form2(); } } } return FrmSingle; } }
有些小夥伴或許會好奇,為什麽還要多加一次if條件判定,是因為多線程存在競爭的資源的問題,如果兩個線程同時運行lock外層的if (FrmSingle == null),都成立,第一條線程加鎖實例化一個對象,解鎖後,如果不加判斷,第二條線程直接實例化一個對象,這就不是單例了。這樣也可以減少多線程情況下每次都需要獲取線程鎖的資源,如果對象已經被實例化了就可以不用加鎖了,節省了系統資源。
五、總結
單例模式,這個知識點並不難,在學校也學習過,但是一些加深的應用例如上面的多線程的情況也是通過博友們的分享才知道會有這個問題,並且知道怎麽去解決。所謂從淺入深,了解清楚並鞏固加深最基本的設計模式方便日後我們繼續學習剩下的設計模式!
C#設計模式——單例模式