2013年7月17日 星期三

設計模式:單例模式 (Singleton Pattern)

單例模式 (Singleton Pattern),以下程式碼以 C# 為例

說明:
讓一個類別只能有一個實例(Instance)的方法。
產生單一實例的方式:
懶漢方式(Lazy initialization):第一次使用時,才產生實例。
餓漢方式(Eager initialization):class 載入時就產生實例,不管後面會不會用到。

範例:
對同一個類別,分別取得 a、b 實例,而 a == b。

希望達成如下的效果
static void Main(string[] args)
{
    // 產生第一個實例
    Singleton a = Singleton.GetInstance();
    Console.WriteLine("a.test = {0}", a.test); // a.test = 1
    a.test = 10; // 將第一個實例的 test 值,改為 10
    Console.WriteLine("a.test = {0}", a.test); // a.test = 10

    // 產生第二個實例
    Singleton b = Singleton.GetInstance();
    Console.WriteLine("b.test = {0}", b.test); // b.test = 10

    Console.WriteLine(b == a); // True, b 跟 a 是同一個實例 

    Console.Read();
}
執行結果: 
a.test = 1
a.test = 10
b.test = 10
True

實現重點在於,確保 class 回傳的實例,都是同一個,有以下兩種做法。

懶漢方式:第一次使用時,才產生實例
class Singleton
{
    // 多執行緒,lock 使用
    private static readonly object thisLock = new object();

    // 將唯一實例設為 private static
    private static Singleton instance;

    public int test = 1;

    // 設為 private,外界不能 new
    private Singleton()
    {
    }

    // 外界只能使用靜態方法取得實例
    public static Singleton GetInstance()
    {
        // 先判斷目前有沒有實例,沒有的話才開始 lock,
        // 此次的判斷,是避免在有實例的情況,也執行 lock ,影響效能
        if (null == instance)
        {
            // 避免多執行緒可能會產生兩個以上的實例,所以 lock
            lock (thisLock)
            {
                // lock 後,再判斷一次目前有無實例
                // 此次的判斷,是避免多執行緒,同時通過前一次的 null == instance 判斷
                if (null == instance)
                {
                    instance = new Singleton();
                }
            }
        }

        return instance;
    }
}

餓漢方式:class 載入時,即產生實例
public sealed class Singleton
{
    // 設為 static,載入時,即 new 一個實例
    private static readonly Singleton instance = new Singleton();

    public int test = 1;

    // 設為 private,外界不能 new
    private Singleton()
    {
    }

    // 使用靜態方法取得實例,因為載入時就 new 一個實例,所以不用考慮多執行緒的問題
    public static Singleton GetInstance()
    {
        return instance;
    }
}

相關連結:設計模式整理列表

沒有留言:

張貼留言