Singleton心得筆記

  • 2879
  • 0
  • C#
  • 2010-03-17

Singleton…

那天看到點部落的高手分享Singleton

忽然想要自己也記錄一下心得

 

其實我對這個pattern算是特別有印象

為什麼會特別印象深刻呢?

第一:當初小弟在寫actionscript做flash動畫時因為flash的動畫中有時會需要設定某些物件只能在同一場景出現一個

(這些情況使用singleton就很方便,把只能產生一個的責任讓物件本身自己來背算是很適當的處理方式。)

第二:有一次小弟問同事,你覺得哪種pattern最簡單,同事跟我說singleton最簡單,小弟笑了…

 

關於Singleton這個pattern

其實說簡單也沒那麼簡單

講起來好像很繞舌

其實我想說的是這個pattern要寫很簡單,但是也是有些小地方要注意

小弟分享一下讀書心得~

 

首先一般來說singleton最基本的兩種寫法


class Singleton
{
    private static Singleton _singleton;
    private Singleton() { }
    public static Singleton GetInstance()
    {
        if (_singleton == null)
        {

            _singleton = new Singleton();
        }
        return _singleton;
    }    
}

 


class Singleton
{
    private readonly static Singleton _singleton = new Singleton();

    private Singleton() { }
    public static Singleton Instance
    {
        get
        {
            return _singleton;
        }
    }     
}

第一種寫法乍看之下比較不占資源,畢竟成是沒呼叫到Singleton.GetInstance()就永遠不會產生一個singleton物件

但是每一次的呼叫GetInstance就要不斷的判斷if (_singleton == null)也是一個開銷

第二種則是在程式開始執行就產生了一個singleton物件

小弟是覺得如果不一定會instance的話,那也就不需要特地使用它了(將他加到專案中)

當然實務上還是需要在判斷要用哪種做法

 

另外當使用第一種做法實需要多判斷多執行緒的問題

首先我將第一種做法改成以下


class Singleton
{
    private static Singleton _singleton;
    public static int count = 0;

    private Singleton() { }
    public static Singleton GetInstance()
    {
        Thread.Sleep(1000);
        if (_singleton == null)
        {
            count++;
            _singleton = new Singleton();
        }
        return _singleton;
    }

    public string GetCount()
    {
        return count.ToString();
    }
}

每次GetInstance都要等一秒,這樣我比叫好模擬

然後我呼叫的程式如下


Singleton singleton, singleton1;
Action act = new Action(delegate()
{
    singleton = Singleton.GetInstance();
});

Action act1 = new Action(delegate()
 {

     singleton1 = Singleton.GetInstance();
 });
IAsyncResult actResult = act.BeginInvoke(null, null);
IAsyncResult act1Result = act1.BeginInvoke(null, null);
WaitHandle[] waithandlearray = new WaitHandle[] { actResult.AsyncWaitHandle, act1Result.AsyncWaitHandle };
while (!WaitHandle.WaitAll(waithandlearray, 3000, false))
{
}            
Console.WriteLine(Singleton.count.ToString());

結果跑到18行時程式給我的count是2。

這就證明了第一種寫法在多執行緒是有可能會出錯的

所以要改成


class Singleton
{
    private static Singleton _singleton;
    private static Object thisLock = new Object();

    private Singleton() { }
    public static Singleton GetInstance()
    {
        if (_singleton == null)
        {
            lock (thisLock)
            {
                _singleton = new Singleton();
            }
        }
        return _singleton;
    }
}

 

 

這樣在多執行緒的呼叫中才能確保只會產生一個Singleton物件

如果Singleton不能防止產生超過一個物件的話,那麼這模式也就完全沒任何意義了不是?

這是需要注意的。

 

有問題請各位大大多多指教,謝謝