2013年10月29日 星期二

Design Pattern : Chain of Responsibility

Design Pattern : Chain of Responsibility

Chain of Responsibility 可將所有職責鍊在一起, 使用者可直接發動開頭的第一件職責, 第一件職責做完後就會去啟動第二件第三件 … etc

底下的例子為去洗車的時候,通常有三個步驟:洗車 -> 打蠟 -> 曬曬陽光做日光浴
如果是開去給洗車場洗的話,其實我們就不需要知道太多細節,可以去吃個晚餐再回來就好。
這時候就可以使用Chain of Responsibility

1.  Handler interface
public interface ICarWashHandler
{
  
ICarWashHandler NextStep { set; get; }
   
void Service<T>(T obj);
}

u  Handler可以看出職責鍊是如何運作的, 我們只要將下一個Handler存放在NextStep,在Service動作的時候做完本身的職責後,再呼叫NextStep.Service就可以一直往下做完整個職責鍊了。

2.  實作Handler

u   第一件職責: 洗車:CarShower

public class CarShower:ICarWashHandler
{
  
public ICarWashHandler NextStep{ get; set;}

   
public void Service<T>(T obj)
    {
      
object client = obj;
      
if (typeof(T).Name.ToString() == "Client")
       {
          
String msg = String.Format(
               
"Car washed! (Customer : {0} {1})",
                (client
as Client).Name,
                (client
as Client).PhoneNumber);
          
Console.WriteLine(msg);
       }
      
if(this.NextStep!=null)
       {
          
this.NextStep.Service(obj);
       }
      
else //Set the default NextStep
      
{
           
this.NextStep = new CarWaxing();
           
this.NextStep.Service(obj);
       }

    }
}

u  第二件職責: 打蠟:CarWaxing
public class CarWaxing:ICarWashHandler
{
  
public ICarWashHandler NextStep{get;set;}
  
public void Service<T>(T obj)
   {
     
object client = obj;
     
if (typeof(T).Name.ToString() == "Client")
      {
         
String msg = String.Format(
              
"Car waxing! (Customer : {0} {1})",
               (client
as Client).Name,
               (client
as Client).PhoneNumber);
         
Console.WriteLine(msg);
      }
     
if (this.NextStep != null)
      {
         
this.NextStep.Service(obj);
      }
     
else //Set the default NextStep
     
{
         
this.NextStep = new CarSunBathing();
         
this.NextStep.Service(obj);
      }
   }
}


u  第三件職責: 日光浴:CarSunBathing
public class CarSunBathing:ICarWashHandler
{
  
public ICarWashHandler NextStep { get; set; }
  
public void Service<T>(T obj)
   {
     
object client = obj;
     
if (typeof(T).Name.ToString() == "Client")
      {
         
String msg = String.Format(
            
"Car sunbathing! (Customer : {0} {1})",
             (client
as Client).Name,
             (client
as Client).PhoneNumber);
         
Console.WriteLine(msg);
      }
     
if (this.NextStep != null)
      {
         
this.NextStep.Service(client);
      }
     
else //Set the default NextStep
     
{
         
Console.WriteLine("Car is great now!");
      }
   }
}


3.      主程式
Client JB = new Client("JB", "0911-29X-XXX");
ICarWashHandler carWash1 = new CarShower();
carWash1.Service<
Client>(JB);

結果:
Car washed! (Customer : JB 0911-29X-XXX)
Car waxing! (Customer : JB 0911-29X-XXX)
Car sunbathing! (Customer : JB 0911-29X-XXX)
Car is great now!


4.      我們也可以手動指定每個職責的下一個為哪個職責,例如我老婆看車子很髒想要洗兩次:
Client Lily = new Client("Lily", "0930-8XX-XXX");
ICarWashHandler carWash2 = new CarShower();
carWash2.NextStep =
new CarShower(); //指定下一個責任為 (再洗車一次)
carWash2.Service<Client>(Lily);

結果:
Car washed! (Customer : Lily 0930-8XX-XXX)
Car washed! (Customer : Lily 0930-8XX-XXX)
//洗了兩次
Car waxing! (Customer : Lily 0930-8XX-XXX)
Car sunbathing! (Customer : Lily 0930-8XX-XXX)
Car is great now!


5.      另外如果遇到某個無法處理目前要求的Handler Handler(職責)也可以選擇不處理直接丟給下一個。
例如 消光的車洗車後不用打蠟,這時候只要在打蠟的Handler中加上判斷就行了。
6.      雖然Chain of Responsibility降低耦合,但是只要職責一多,Performance就會被拖累。


沒有留言:

張貼留言