Chain of Responsibility Pattern

Chain of Responsibility Pattern用途

Chain of Responsibility Pattern類似一個結構化的switch,輸入若不符合條件就會給下一個case處理。

 

Chain of Responsibility Pattern實作結構

 

基本所需的結構有upSendData、SetUpSendData、Processor三個。

upSendData:主要是記錄下一個Processor所處裡的資料。

SetUpSendData:用來設定紀錄upSendData的資料,也就是結構連結下一個處理資料的設定。

Processor:主要執行目前的結構要處理的事情。

Chain of Responsibility Pattern設計概念

1.Processor設計:需要有一個判斷是否可以被當下Processor處理的規則,若不符合此規則會檢查是否還有下一個檢查項目,若已經是最後一個檢查項目,則作沒有符合項目的處理,若有下一個檢查項目會call下一個檢查項目的Processor繼續做下去。(如下範例)


public override void Processor(input)
{
if (判斷條件)
{
...
}
else
{
if (null != upSendData)
upSendData.Processor(input);
}
}

 

2.SetUpSendData和upSendData設計:SetUpSendData和upSendData基本上是固定的寫法,SetUpSendData用來設定下一個檢查項目的upSendData讓upSendData.Processor可以往下串接。(如下範例)


protected SendDataHandler upSendData;
public void SetUpSendData(SendDataHandler upSendData)
{
this.upSendData = upSendData;
}


abstract class SendDataHandler
{
protected Dictionary<string, string> D;
protected SendDataHandler upSendData;
public SendDataHandler(string tagstr)
{
D = new Dictionary<string, string>();
string[] ss = tagstr.Split(';');
string[] tmp0 = ss[0].Split(',');
string[] tmp1 = ss[1].Split(',');
for (int i = 0; i < tmp0.Count(); i++)
D.Add(tmp0[i],tmp1[i]);
}
public void SetUpSendData(SendDataHandler upSendData)
{
this.upSendData = upSendData;
}
abstract public void Processor(object key, object value, ref object Out);
}

 

說明:範例要做一個把某些關鍵字A對應成為B字串,D變數用於存取A字串和B字串的對應,SendDataHandler用於初始化D變數資料,SetUpSendData用於設定upSendData串接的資料,Processor主要處理A字串的某些關鍵字改為B字串的功能以及判斷是否符合要處理的資料。


class ToServerCommonClass : SendDataHandler
{
public ToServerCommonClass(string tagstr) : base(tagstr) { }
public override void Processor(object key, object value, ref object Out)
{
string _key = key.ToString();
if (D.ContainsKey(_key)) {
string _value = ((IDictionary<string, string>)value)[_key];
if (string.IsNullOrWhiteSpace(_value)) return;
((List)Out).Add(D[_key] + "=" + _value);
}
else
{
if (null != upSendData)
upSendData.Processor(key, value,ref Out);
}
}
}

 

說明:如果D變數裡面有符合輸入的關鍵字,且輸入的value變數找的到該關鍵字的對應資料,就將字串組合後輸出,若value變數沒有找到關鍵字的對應資料就不做處理,另外如前面所提到的若D對應表沒有找到此輸入所對應的字串,則程式會去找是否有下一個Processor可以處理,在此範例中,若找不到下一個Processor處理時,就不處理了。

 


class ToServerResponseClass : SendDataHandler
{
public ToServerResponseClass(string tagstr) : base(tagstr) { }
public override void Processor(object key, object value, ref object Out)
{
string _key = key.ToString();
//string _value = value.ToString();
if (D.ContainsKey(_key)) {
string _value = ((IDictionary)value)[_key];
if (string.IsNullOrWhiteSpace(_value)) return;
((List)Out).Add(D[_key] + "=" + _value);
((List)Out).Add("Q=P");
}
else
{
if (null != upSendData)
upSendData.Processor(key, value,ref Out);
}
}
}

說明:大致跟上一段code一樣,差別在處理字串輸出多了一個”Q=P”字串,讓string list裡面多了一筆資料。


ToServerCommonClass CC = new ToServerCommonClass("NAS,BBB,CCC;About iTe2,QQQ,RRR");
ToServerResponseClass RC = new ToServerResponseClass("網路儲存伺服器;關於詮力");
public static void Main(string[] args)
{
CC.SetUpSendData(RC);
string[] StrA = {"NAS","網路儲存伺服器"};
List bj = new List(20);
object bjtmp = bj;
foreach(string i in StrA)
CC.Processor(i, "VVV", ref bjtmp);
bj = (List)bjtmp;
}

說明:一開始先宣告CC、RC兩個處理類別,並且初始化這兩個類別能夠處理的字串對應表,然後程式進入的時候將CC處理類別與RC處理類別串起來,這樣CC處理類別無法處裡的時候就會給RC處理類別處理了,接下來在宣告一個字串陣列StrA,裡面有兩個字串,剛好一個可以給CC類別處理,一個可以給RC類別處理,然後開始處理字串,迴圈第一圈輸入的key=”NAS”,value=”VVV”所以CC類別處理結果為bjtmp加入字串”About iTe2=VVV”,接下來迴圈第二圈輸入的key=”網路儲存伺服器”,value=”VVV”因為CC類別不能處理,所以輸入值會向下一個處理丟,丟給RC類別處理,RC類別可以處理”網路儲存伺服器”字串,所以bjtmp加入字串”關於詮力=VVV”和”Q=P”兩字串,接下來跳出迴圈後將物件bjtmp轉給bj string list結束程式。

結語:Chain of Responsibility Pattern其實算滿常可以使用的一種寫程式的方法,不過有個小缺點就是會比一般的if方法或是switch方法處理起來還要慢,但是優點是方便管理、模組化、變化性高…等等優點,但是相對的,設計的時間成本也相對較多且開發起來較複雜,需不需要用到Chain of Responsibility Pattern我覺得還是要看狀況使用,而不是都改成Chain of Responsibility Pattern的方式就是最好的方法。


發表迴響

這個網站採用 Akismet 服務減少垃圾留言。進一步瞭解 Akismet 如何處理網站訪客的留言資料