1. 緣起:
假設我們的用戶管理系統要求用戶的 ID 和 Name 都必須是唯一的,并且用戶的 ID 和 Name 一經確定就不能被修改。而且管理系統經常需要根據 ID 來查找 Name ,也經常需要根據 Name 來查找 ID 。根據這樣的需求,我們可以考慮使用一個 Dictionary 來將 ID 和 Name 緩存起來,通常 ID 作為 Key , Name 作為 Value 。這樣便可實現通過 ID 查詢 Name 的快速查找,但是,通過 Name 查找 ID 就不是那么快了,因為涉及到對 Dictionary 的 Values 做遍歷的操作。那么,有可能使得通過 Name 查找 ID 的速度與通過 ID 查找 Name 的速度一樣快嗎?
于是,我設計了 ESBasic.ObjectManagement.Cache.IBidirectionalMapping (雙向映射)來解決這個問題。
雙向映射的形象示意圖如下:
2. 適用場合:
如果滿足以下的條件,則可以使用雙向映射:
(1) Key 是唯一的, Value 也是唯一的。
(2) 需要對 Key 和 Value 做緩存。
(3) 經常需要根據 Key 來查找 Value 。
(4) 經常需要根據 Value 來查找 Key 。
3 .設計思想與實現
IBidirectionalMapping 接口定義如下:
/// IBidirectionalMapping雙向映射。即Key和Value都是唯一的,在這種情況下使用IBidirectionalMapping可提升依據Value查找Key的速度。
/// 該接口的實現必須是線程安全的。2008.08.20
/// </summary>
public interface IBidirectionalMapping < T1,T2 >
{
int Count{ get ;}
/// <summary>
/// Add添加映射對。如果已經有相同的key/value存在,則會覆蓋。
/// </summary>
void Add(T1t1,T2t2);
void RemoveByT1(T1t1);
void RemoveByT2(T2t2);
T1GetT1(T2t2);
T2GetT2(T1t1);
bool ContainsT1(T1t1);
bool ContainsT2(T2t2);
/// <summary>
/// GetAllT1ListCopy返回T1類型元素列表的拷貝。
/// </summary>
IList < T1 > GetAllT1ListCopy();
/// <summary>
/// GetAllT2ListCopy返回T2類型元素列表的拷貝。
/// </summary>
IList < T2 > GetAllT2ListCopy();
}
該接口使用了兩個泛型參數,根據上面的描述,一個泛型參數表示 Key 的類型,另一個泛型參數表示 Vlaue 的類型。由于,在雙向映射中, Key 和 Value 是對稱的,所以我沒有使用 TKey 和 TValue 來命名它們,而是使用 T1 和 T2 。
在實現 BidirectionalMapping 時,我們使用兩個 Dictionary 來完成雙向映射的功能。一個 Dictionary 以 T1 為 Key , T2 為 Value ;另一個剛好反過來。
在實現的具體過程中,要注意以下幾點:
(1) 為了允許在多線程的環境中使用雙向映射,所以 BidirectionalMapping 必須在對內部 Dictionary 操作的時候進行加鎖控制。
(2) 在實現 Add 方法添加一個“映射對”的時候,必須判斷當前是否已經存在了相同的值,如果存在,則先刪除舊的映射對,再添加新的映射對。
(3) 要注意一個細節, GetAllT1ListCopy 和 GetAllT2ListCopy 的實現都使用了 lock ,這是因為在拷貝的時候會對其 Keys 或 Values 進行 foreach 遍歷,而在對 Dictionary 中的元素進行 foreach 遍歷的時候,如果同時向其中添加或刪除元素,則 foreach 操作是會拋出異常的。
4. 使用時的注意事項
BidirectionalMapping 提升了通過 Name 查找 ID 的速度,這是通過使用了更大的內存來做到的,是典型的“空間換時間”的例子。所以,對于巨大規模的映射對的緩存,要注意內存的使用問題。
另外,映射對中的兩個元素的類型不一定非是 ID 或 Name 這樣的簡單對象,實際上,非常復雜的對象也可以緩存在雙向映射中,只要其 GetHashCode 方法實現的恰當就不會有任何問題。
5. 擴展
雙向映射 BidirectionalMapping 暫時沒有任何擴展。注:ESBasic源碼可到 http://esbasic.codeplex.com/ 下載。
ESBasic討論:37677395
ESBasic開源前言
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
