1. 緣起:
假設(shè)我們的訂單處理系統(tǒng)所要處理的訂單是有優(yōu)先級(jí)的,也就是說(shuō),不同的訂單類型所要求被處理的緊迫程度不同,對(duì)那些優(yōu)先級(jí)高的注單要先處理,對(duì)于優(yōu)先級(jí)低的注單可稍后處理。對(duì)于處于同一優(yōu)先級(jí)的訂單了,就按照其到達(dá)的先后順序進(jìn)行處理。
這是一個(gè)典型的管理具有優(yōu)先級(jí)的對(duì)象的需求,注單就是具有優(yōu)先級(jí)( With Priority )的對(duì)象。我設(shè)計(jì)了 ESBasic.ObjectManagement.Managers.IPriorityManager 優(yōu)先級(jí)管理器(確切地說(shuō),應(yīng)該稱之為“具有優(yōu)先級(jí)對(duì)象的管理器”)來(lái)對(duì)類似的對(duì)象進(jìn)行管理。
優(yōu)先級(jí)管理器的形象示意圖如下:
2. 適用場(chǎng)合:
如果你的系統(tǒng)需要對(duì)被管理的對(duì)象進(jìn)行優(yōu)先級(jí)分級(jí),并滿足以下條件,則可使用 IPriorityManager :
(1) 對(duì)象需要按優(yōu)先級(jí)別( PriorityLevel )進(jìn)行分類。
(2) 優(yōu)先級(jí)別的劃分是固定的,不會(huì)隨系統(tǒng)的運(yùn)行而發(fā)生變化。
(3) 對(duì)處于同一優(yōu)先級(jí)別的對(duì)象,采用先來(lái)后到的順序進(jìn)行“第二優(yōu)先級(jí)”的高低確定。
(4) 優(yōu)先級(jí)別可以使用 >=0 的連續(xù)整數(shù)來(lái)表示。
3 .設(shè)計(jì)思想與實(shí)現(xiàn)
在前面的敘述中,具有優(yōu)先級(jí)對(duì)象的管理器的功能職責(zé)是相當(dāng)清晰明了的,在進(jìn)入其實(shí)現(xiàn)之前,首先我們要解決的一個(gè)問題是,如何對(duì)處于同一優(yōu)先級(jí)別的對(duì)象進(jìn)行管理。根據(jù)前面的需求描述,如果兩個(gè)對(duì)象處于相同的優(yōu)先級(jí)別,則先到達(dá)的對(duì)象的優(yōu)先程度(即所謂的“第二優(yōu)先級(jí)”)更高。
我使用 ESBasic.ObjectManagement.Managers. ISamePriorityObjectManager (同一優(yōu)先級(jí)別對(duì)象管理器)來(lái)管理屬于同一優(yōu)先級(jí)別的所有對(duì)象,其接口定義如下:
{
/// <summary>
/// AddWaiter添加一個(gè)等待者。如果等待者在管理器中已經(jīng)存在,則直接返回。
/// </summary>
void AddWaiter(Twaiter);
/// <summary>
/// Count當(dāng)前管理器中等待者的數(shù)量。
/// </summary>
int Count{ get ;}
/// <summary>
/// GetNextWaiter返回等待時(shí)間最長(zhǎng)的waiter。
/// 注意,返回時(shí)并不會(huì)從等待列表中刪除waiter。如果要?jiǎng)h除某個(gè)等待者,請(qǐng)調(diào)用RemoveWaiter。
/// </summary>
TGetNextWaiter();
/// <summary>
/// GetWaitersByPriority按照等待者加入的先后順序返回等待者數(shù)組,數(shù)組中index越小的等待者其等待時(shí)間越長(zhǎng),其優(yōu)先級(jí)也越高。
/// </summary>
T[]GetWaitersByPriority();
/// <summary>
/// RemoveWaiter從管理器中移除指定的等待者。
/// </summary>
void RemoveWaiter(Twaiter);
/// <summary>
/// Clear清空管理器中的所有等待者。
/// </summary>
void Clear();
/// <summary>
/// Contains管理器中是否存在指定的等待者。
/// </summary>
bool Contains(Twaiter);
}
在 ISamePriorityObjectManager 所表述的語(yǔ)義環(huán)境中,被管理的對(duì)象稱為“等待者” waiter ――這表示一個(gè)對(duì)象等待被處理。
關(guān)于 SamePriorityObjectManager 的實(shí)現(xiàn),有以下幾點(diǎn)需要說(shuō)明:
(1) 其內(nèi)部是使用 LinkedList 而不是 Queue 來(lái)存儲(chǔ)等待者的,其主要原因在于 SamePriorityObjectManager 需要支持移除管理器中任一等待者的 RemoveWaiter 方法。由于 Queue 本身不支持任意位置的刪除功能,所以我使用了 LinkedList 。新加入的等待者將被放在 LinkedList 的最后位置。
(2) 當(dāng)管理器中沒有任何等待者時(shí), GetNextWaiter 方法將返回 default(T) ,如果 T 是值類型,則此時(shí) GetNextWaiter 返回的可能并不是一個(gè)你所期望的對(duì)象。所以,如果 T 是值類型,在調(diào)用 GetNextWaiter 之前先訪問一下其 Count 屬性確保管理器中還有等待者存在。
(3) SamePriorityObjectManager 使用了前面介紹的 SmartRWLocker 來(lái)對(duì)內(nèi)部的 waiterList 進(jìn)行讀寫鎖控制。
在討論完 SamePriorityObjectManager 的實(shí)現(xiàn)以后,我們將注意力轉(zhuǎn)移到本節(jié)的主角 IPriorityManager 上來(lái), IPriorityManager 的接口定義如下:
/// IPriorityManager具有優(yōu)先級(jí)的對(duì)象的管理器。
/// </summary>
/// <typeparamname="T"> 被管理的對(duì)象的類型,必須從IPriorityObject繼承。 </typeparam>
public interface IPriorityManager < T > : ISamePriorityObjectManager < T > where T: class , IPriorityObject
{
int PriorityLevelCount{ get ; set ;}
}
IPriorityManager 接口直接從 ISamePriorityObjectManager 繼承,并沒有多加任何方法,唯一增加的就是一個(gè) PriorityLevelCount 屬性和要求被管理的對(duì)象的類型必須是從 IPriorityObject 接口繼承的一個(gè)泛型約束。
PriorityLevelCount 用于設(shè)定你的系統(tǒng)需要有幾種優(yōu)先級(jí)別。比如,我的訂單基于緊急的優(yōu)先級(jí)可分為緊急、普通、不緊急三種,那么就可將 PriorityLevelCount 屬性設(shè)置為 3 。
一個(gè)類型從 IPriorityObject 接口繼承,就表明它的實(shí)例是具有優(yōu)先級(jí)屬性的對(duì)象。
/// IPriorityObject具有優(yōu)先級(jí)的對(duì)象的接口。
/// </summary>
public interface IPriorityObject
{
int PriorityLevel{ get ;}
}
為什么 ISamePriorityObjectManager 沒有要求被管理的對(duì)象繼承自 IPriorityObject 接口了? 這是因?yàn)樵? ISamePriorityObjectManager 的職責(zé)中,其僅僅是根據(jù)對(duì)象的先后順序來(lái)確定“第二優(yōu)先級(jí)”的,這并不是真正意義上的優(yōu)先級(jí)別,所以沒有必要為其單獨(dú)抽象出一個(gè) IPriorityObject 接口來(lái)。同時(shí), ISamePriorityObjectManager 不要求被管理的對(duì)象繼承自 IPriorityObject 接口也是為了擴(kuò)大其被單獨(dú)復(fù)用的范圍。
IPriorityManager 接口直接從 ISamePriorityObjectManager 接口繼承,說(shuō)明 IPriorityManager 實(shí)際上要做工作與 ISamePriorityObjectManager 是相同的,只不過 IPriorityManager 管理的對(duì)象需要首先按優(yōu)先級(jí)別進(jìn)行分類,然后再使用 ISamePriorityObjectManager 管理處于同一優(yōu)先級(jí)別的對(duì)象。
接下來(lái)我們看 PriorityManager 的具體實(shí)現(xiàn)。
在 PriorityManager 中,有這樣的一個(gè) 約定 :優(yōu)先級(jí)別是用 int 表示的,其值是從 0 開始連續(xù)的一串整數(shù),整數(shù)值越小,表明優(yōu)先級(jí)越高。當(dāng) Initialize 方法被執(zhí)行后,優(yōu)先等級(jí)的范圍就被固定下來(lái)。比如 PriorityLevelCount 值設(shè)為 4 ,則 PriorityManager 所支持的優(yōu)先等級(jí)即為: 0 , 1 , 2 , 3 。
基于這樣的約定, PriorityManager 內(nèi)部使用了一個(gè) ISamePriorityObjectManager 數(shù)組,數(shù)組的索引值就對(duì)應(yīng)著優(yōu)先級(jí)別值。比如,數(shù)組中 index 為 1 的 ISamePriorityObjectManager 管理器中的所有對(duì)象的優(yōu)先級(jí)別值都是 1 。
有了這兩點(diǎn)認(rèn)識(shí),再看 PriorityManager 的源碼就相當(dāng)容易了,下面是其中的關(guān)鍵點(diǎn):
(1) 在類似 AddWaiter 、 RemoveWaiter 這樣的方法實(shí)現(xiàn)中,都是先通過其參數(shù)對(duì)象的 PriorityLevel 屬性定位到對(duì)應(yīng)的 ISamePriorityObjectManager 管理器,然后再做進(jìn)一步的處理的。
(2) 如果目標(biāo)對(duì)象的 PriorityLevel 屬性值超過了約定的范圍, PriorityManager 會(huì)根據(jù)當(dāng)前的情況做靈活的處理。比如,如果是調(diào)用 AddWaiter 加入一個(gè)這樣的對(duì)象,則會(huì)拋出一個(gè)“不支持該優(yōu)先級(jí)別”的異常;而如果是在類似 RemoveWaiter 這樣的方法中,則會(huì)忽略這個(gè)對(duì)象。
(3) 如果 PriorityManager 管理器中沒有任何對(duì)象時(shí), PriorityManager 的 GetNextWaiter 方法直接返回 null ,而不是 default(T) ,這是因?yàn)樵? PriorityManager 定義的泛型約束中,要求 T 必須是一個(gè)引用類型。這就沒有了前面提到的 SamePriorityObjectManager 的 GetNextWaiter 方法的返回值可能導(dǎo)致的問題。
(4) GetWaitersByPriority 方法返回的對(duì)象數(shù)組具有這樣的特征:優(yōu)先級(jí)別越高的對(duì)象,其在數(shù)組中的位置索引就越??;同一優(yōu)先級(jí)別的對(duì)象,加入時(shí)間越早的,其在數(shù)組中的位置索引越小。
4. 使用時(shí)的注意事項(xiàng)
(1) 如果你的系統(tǒng)僅僅需要按照對(duì)象的到達(dá)順序來(lái)決定先后處理的順序,那么直接使用 ISamePriorityObjectManager 就可以滿足需求了,沒有必要使用 IPriorityManager 這個(gè)更復(fù)雜的類。使用 ISamePriorityObjectManager 還有一個(gè)好處就是,被管理的對(duì)象不需要實(shí)現(xiàn) IPriorityObject 接口,這樣使用起來(lái)會(huì)更加方便。
(2) 如果在你的系統(tǒng)中不是使用 0,1,2,3… 這樣的數(shù)值來(lái)表示優(yōu)先級(jí)別的,那么你可以建立一個(gè)轉(zhuǎn)換映射來(lái)完成優(yōu)先級(jí)別值到數(shù)字的轉(zhuǎn)換。并遵從 PriorityManager 所要求的約定。
(3) PriorityManager 的 Initialize 方法一旦被調(diào)用后,其 PriorityLevelCount 屬性便不應(yīng)該被修改。或者說(shuō),即使該屬性在之后被修改,也不會(huì)產(chǎn)生任何效果。
5. 擴(kuò)展
優(yōu)先級(jí)管理器 PriorityManager 暫時(shí)沒有任何擴(kuò)展。
注:ESBasic源碼可到
http://esbasic.codeplex.com/
下載。
ESBasic討論:37677395
ESBasic開源前言
ESBasic 可復(fù)用的.NET類庫(kù)(14) -- 優(yōu)先級(jí)管理器 IPriorityManager
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

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