情境:微軟的windows xp作業系統,ctrl+alt+del鍵都會彈出一個windows工作管理員(這時不關閉這個工作管理員),繼續ctrl+alt+del鍵還是一個windows工作管理員。鑒於本人水平有限,上面的情境舉例可能不合適,但是很接近一個基本的設計模式:單例模式。Code is cheap.下面用c#代碼類比出一個類似工作管理員的建立:
Code
using System;
/// <summary>
/// Singleton 單例模式
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
if (wtm==null)
{
wtm = new WindowsTaskManager();
}
return wtm;
}
}
/// <summary>
/// 用戶端調用
/// </summary>
public class Client {
static void Main(string[] args)
{
WindowsTaskManager myWtm = WindowsTaskManager.CreateSingleWtm();
WindowsTaskManager myWtm1 = WindowsTaskManager.CreateSingleWtm();
if (myWtm==myWtm1)
{
Console.WriteLine("兩個對象是相同的執行個體.");
}
}
}
上面建立執行個體的基本思想是new一個對象的時候,判斷靜態類變數是否已經有執行個體,建構函式私人,這樣外部代碼不能直接new來執行個體化對象。這是因為我們都知道所有類都有建構函式,不編碼寫建構函式則系統預設產生無參數的構造方法,但如果有顯式定義的構造方法,預設的就會失效。ps:在定義可序列化的類的時候,預設建構函式是必須的,所以如果你顯式定義了一個帶參數的構造方法,一定不能忘記要再寫一個沒有參數的構造方法。
好了,上面的代碼ms已經簡單的實現了對唯一執行個體的受控訪問。不過在多線程的程式中,上面的代碼會有可能建立多個執行個體的。給進程加把鎖,用lock解決一下:Code
using System;
using System.Threading;
/// <summary>
/// Singleton
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private static readonly object syncRoot = new object();// 程式運行時建立一個靜態唯讀進程輔助對象
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
lock (syncRoot)
{
if (wtm == null)
{
wtm = new WindowsTaskManager();
}
}
return wtm;
}
}
上面那種做法可以建立單一執行個體,可是每次調用建立方法時,都要lock,影響效能,有一種雙重鎖定的方法:Code
using System;
using System.Threading;
/// <summary>
/// Singleton 雙重鎖定
/// </summary>
public class WindowsTaskManager
{
private static WindowsTaskManager wtm;
private static readonly object syncRoot = new object();// 程式運行時建立一個靜態唯讀進程輔助對象
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
if (wtm == null) //當wtm為空白時,如果這時有兩個線程同時調用CreateSingleWtm方法
{
lock (syncRoot)
{
if (wtm == null) // 很關鍵,沒有這個判斷,進入的兩個線程就可以建立兩個執行個體了
{
wtm = new WindowsTaskManager();
}
}
}
return wtm;
}
}
最後再看一個所謂的餓漢式單例類:Code
using System;
using System.Threading;
/// <summary>
/// Singleton sealed防止派生增加執行個體
/// </summary>
public sealed class WindowsTaskManager
{
private static readonly WindowsTaskManager wtm=new WindowsTaskManager();
private WindowsTaskManager()
{
}
public static WindowsTaskManager CreateSingleWtm()
{
return wtm;
}
}