如果今天有一個需求,希望使用將不同類型的資料,統一的放入 queue ,統一管理。那這樣的情況...
我們來解析一下需求,它想要統一管理所使用的 queue ,所以可以畫出以下的概念圖
用白話來說,所有建立的 queue , 都要加入 queue router 之中,但資料要如何個自放到對應的 queue 之中?
試著用 TDD 的方式進行開發,在加入第一個 Test case 時,建立一個 ConcurrentQueue 的 queue 還很順利。
public class QueueRouter
{
private ConcurrentQueue<int> _queue;
public void AddQueue(ConcurrentQueue<int> queue){...}
public void Enqueue(int i){...}
}
但是接下來,建立 ConcurrentQueue 時,就會發現,很多問題浮出水面,AddQueue
與 Enqueue
都會發生類別轉換錯誤的問題。
當然,也可以用硬幹,俗稱暴力破解法來滿足下面的需求。
public class QueueRouter
{
private ConcurrentQueue<int> _queue;
private ConcurrentQueue<string> _queueString;
public void AddQueue(ConcurrentQueue<int> queue){...}
public void AddQueue(ConcurrentQueue<string> queue){...}
public void Enqueue(int i){...}
public void Enqueue(string i){...}
}
但是,如果支援的資料類型越來越多,難道要一直在 QueueRouter 之中加入 ConcurrentQueue property 與 method 嗎? 這不但不符合 Open-Close 原則外,也間接增加維護開發的困難。
如果將傳入的資料打包,同時有一個標記讓 queue Manager 可以知道新增的資料是屬於那個 queue 的,這種作法的概念圖如下。
public class QueueItem
{
public string Label { get; set; }
public object Payload { get; set; }
}
這時,輸入的資料有 Label
可以做為判斷資料類型的依據,如示意圖表示。Router 可以依據 Label 內的資訊來進行歸類的動作。
在這個例子中,我們可以先參考下列的程式實作。
public class QueueRouter
{
private ConcurrentQueue<int> _queue;
private ConcurrentQueue<string> _strQueue;
public void AddQueue(ConcurrentQueue<int> queue)
{
_queue = queue;
}
public void AddQueue(ConcurrentQueue<string> queue)
{
_strQueue = queue;
}
public void Enqueue(QueueItem item)
{
if (item.Label == typeof(int).ToString())
{
_queue.Enqueue((int) item.Payload);
}
if (item.Label == typeof(string).ToString())
{
_strQueue.Enqueue((string) item.Payload);
}
}
}
目前寫法,因為是利用 .net 的資料類別,都是繼承 object
的特性實作的。所以會有 Boxing / Unboxing 的吃效能的缺點,但這邊我們先不理它。