2013年11月28日 星期四

Design Pattern : Singleton

Design Pattern : Singleton

Definition :
Ensure a class has only one instance and provide a global point of access to it


Singleton通常使用於只能建立某類別的單一個物件,例如 取號碼機(某段時間的號碼唯一)、戶政事務所發身分證(身分字號唯一), 目的是確保不會有多人同時建立或是同時修改這個物件。
我在先前有寫了一篇Singleton in MutiThread AP

裡面有三種利用Singleton建立取號機的方式,但是其實文章中取號的動作卻不是Thread-Safe 雖然程式碼中可以確保Multi-thread中是取得同一個取號機,但是取號的動作其實還必須lock才能確保取號的動作是Thread-Safe,否則還是有可能取道同樣的號碼。 (文章就不修改,留下不經一事不長一智的紀錄 XD

底下是利用Singleton取得每台汽車的CarUid 可以把它想成車牌號碼,必須是唯一的。


1.  Singleton Class :
=>
使用Thread-safe, lazy singleton
=>
注意在實際取得CarUid時,有使用lock以確保Thread-safe

public class CarUidSingleton
{
   
/// Car's Unique id
   
private string Uid = "000000";
   
   
private static readonly object block = new object();
   
   
public static CarUidSingleton GetInstance
    {
       
get
        { 
return InnerClass.instance; }
    }
   
public String GetUid()
    {
        
lock(block)
         { 
           
int _uid = 0;
           
if (int.TryParse(this.Uid, out _uid))
            {
                 _uid++;
                
this.Uid = _uid.ToString().PadLeft(6, '0');
            }
           
else
                 throw
new Exception("The Uid is not correct!");
           
return this.Uid;
        }
     }
    
private class InnerClass
    
{
        
static InnerClass() { }
        
internal static readonly CarUidSingleton instance = new CarUidSingleton();
     }
}

2.  主程式:
=>
剛好拿Async-AwiatTask兩種方式來實做Multi-thread的測試程式

        List<ICar> carList = new List<ICar>();
       
for(int i=0; i<5; i++)
        {

          
carList.Add(new Focus());
            carList.Add(
new Civic());
            carList.Add(
new Fit());
            carList.Add(
new V60());
            carList.Add(
new Accord());
        };

       
Parallel.ForEach(carList, car =>
            {
            
#region Async-Await
                 GetCarUidInfo_UseAsyncAwait(car);
///請參考3.
            
#endregion

             #region
Task
                 GetCarUidInfo_UseTask(car); ///
請參考4.
            
#endregion
           
}
         );
3.  Async-Await:

private
async static void GetCarUidInfo_UseAsyncAwait(ICar car)
{
    
String uid = await GetAsyncCarUid();
    
Console.WriteLine( String.Format("{0}({1})", car.Name, uid));
}

private async static Task<String> GetAsyncCarUid()
{
       
Thread.Sleep(1500);
       
return CarUidSingleton.GetInstance.GetUid();
}

4.  Task:

private static void GetCarUidInfo_UseTask(ICar car)
{
     
Task<String> _task = new Task<String>(
             () =>
CarUidSingleton.GetInstance.GetUid()
       );
       _task.Start();
       _task.ContinueWith(TaskEnded, car);
}

private static void TaskEnded(Task<String> task, object car)
{
      
String uid =  task.Result;
       
Console.WriteLine(
          
String.Format("{0}({1})", (car as ICar).Name, uid));
}


5.  結果:
Fit(000001)
Accord(000002)
Focus(000003)
Civic(000004)
V60(000005)
Fit(000006)
Accord(000007)
Accord(000008)

Focus(000024)
Civic(000025)






沒有留言:

張貼留言