Design Pattern : Chain of Responsibility
底下的例子為去洗車的時候,通常有三個步驟:洗車 -> 打蠟 -> 曬曬陽光做日光浴
如果是開去給洗車場洗的話,其實我們就不需要知道太多細節,可以去吃個晚餐再回來就好。
這時候就可以使用Chain of Responsibility。
1.
Handler interface
public interface ICarWashHandler
{
ICarWashHandler NextStep { set; get; }
void Service<T>(T obj);
}
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);
}
}
}
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);
}
}
}
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!");
}
}
}
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!
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!
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中加上判斷就行了。
例如 消光的車洗車後不用打蠟,這時候只要在打蠟的Handler中加上判斷就行了。
6.
雖然Chain of
Responsibility降低耦合,但是只要職責一多,Performance就會被拖累。