ESBasic 可复用的.NET类库(14) -- 优先级管

系统 1378 0

1. 缘起:

假设我们的订单处理系统所要处理的订单是有优先级的,也就是说,不同的订单类型所要求被处理的紧迫程度不同,对那些优先级高的注单要先处理,对于优先级低的注单可稍后处理。对于处于同一优先级的订单了,就按照其到达的先后顺序进行处理。

这是一个典型的管理具有优先级的对象的需求,注单就是具有优先级( With Priority )的对象。我设计了 ESBasic.ObjectManagement.Managers.IPriorityManager 优先级管理器(确切地说,应该称之为“具有优先级对象的管理器”)来对类似的对象进行管理。

优先级管理器的形象示意图如下:

ESBasic 可复用的.NET类库(14) -- 优先级管理器 IPriorityManager

2. 适用场合:

如果你的系统需要对被管理的对象进行优先级分级,并满足以下条件,则可使用 IPriorityManager

(1) 对象需要按优先级别( PriorityLevel )进行分类。

(2) 优先级别的划分是固定的,不会随系统的运行而发生变化。

(3) 对处于同一优先级别的对象,采用先来后到的顺序进行“第二优先级”的高低确定。

(4) 优先级别可以使用 >=0 的连续整数来表示。

3 .设计思想与实现

在前面的叙述中,具有优先级对象的管理器的功能职责是相当清晰明了的,在进入其实现之前,首先我们要解决的一个问题是,如何对处于同一优先级别的对象进行管理。根据前面的需求描述,如果两个对象处于相同的优先级别,则先到达的对象的优先程度(即所谓的“第二优先级”)更高。

我使用 ESBasic.ObjectManagement.Managers. ISamePriorityObjectManager (同一优先级别对象管理器)来管理属于同一优先级别的所有对象,其接口定义如下:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> public interface ISamePriorityObjectManager < T >
{
/// <summary>
/// AddWaiter添加一个等待者。如果等待者在管理器中已经存在,则直接返回。
/// </summary>
void AddWaiter(Twaiter);

/// <summary>
/// Count当前管理器中等待者的数量。
/// </summary>
int Count{ get ;}

/// <summary>
/// GetNextWaiter返回等待时间最长的waiter。
/// 注意,返回时并不会从等待列表中删除waiter。如果要删除某个等待者,请调用RemoveWaiter。
/// </summary>
TGetNextWaiter();

/// <summary>
/// GetWaitersByPriority按照等待者加入的先后顺序返回等待者数组,数组中index越小的等待者其等待时间越长,其优先级也越高。
/// </summary>
T[]GetWaitersByPriority();

/// <summary>
/// RemoveWaiter从管理器中移除指定的等待者。
/// </summary>
void RemoveWaiter(Twaiter);

/// <summary>
/// Clear清空管理器中的所有等待者。
/// </summary>
void Clear();

/// <summary>
/// Contains管理器中是否存在指定的等待者。
/// </summary>
bool Contains(Twaiter);
}

ISamePriorityObjectManager 所表述的语义环境中,被管理的对象称为“等待者” waiter ――这表示一个对象等待被处理。

关于 SamePriorityObjectManager 的实现,有以下几点需要说明:

(1) 其内部是使用 LinkedList 而不是 Queue 来存储等待者的,其主要原因在于 SamePriorityObjectManager 需要支持移除管理器中任一等待者的 RemoveWaiter 方法。由于 Queue 本身不支持任意位置的删除功能,所以我使用了 LinkedList 。新加入的等待者将被放在 LinkedList 的最后位置。

(2) 当管理器中没有任何等待者时, GetNextWaiter 方法将返回 default(T) ,如果 T 是值类型,则此时 GetNextWaiter 返回的可能并不是一个你所期望的对象。所以,如果 T 是值类型,在调用 GetNextWaiter 之前先访问一下其 Count 属性确保管理器中还有等待者存在。

(3) SamePriorityObjectManager 使用了前面介绍的 SmartRWLocker 来对内部的 waiterList 进行读写锁控制。

在讨论完 SamePriorityObjectManager 的实现以后,我们将注意力转移到本节的主角 IPriorityManager 上来, IPriorityManager 的接口定义如下:

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> /// <summary>
/// IPriorityManager具有优先级的对象的管理器。
/// </summary>
/// <typeparamname="T"> 被管理的对象的类型,必须从IPriorityObject继承。 </typeparam>
public interface IPriorityManager < T > : ISamePriorityObjectManager < T > where T: class , IPriorityObject
{
int PriorityLevelCount{ get ; set ;}
}

IPriorityManager 接口直接从 ISamePriorityObjectManager 继承,并没有多加任何方法,唯一增加的就是一个 PriorityLevelCount 属性和要求被管理的对象的类型必须是从 IPriorityObject 接口继承的一个泛型约束。

PriorityLevelCount 用于设定你的系统需要有几种优先级别。比如,我的订单基于紧急的优先级可分为紧急、普通、不紧急三种,那么就可将 PriorityLevelCount 属性设置为 3

一个类型从 IPriorityObject 接口继承,就表明它的实例是具有优先级属性的对象。

<!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--> /// <summary>
/// IPriorityObject具有优先级的对象的接口。
/// </summary>
public interface IPriorityObject
{
int PriorityLevel{ get ;}
}

为什么 ISamePriorityObjectManager 没有要求被管理的对象继承自 IPriorityObject 接口了? 这是因为在 ISamePriorityObjectManager 的职责中,其仅仅是根据对象的先后顺序来确定“第二优先级”的,这并不是真正意义上的优先级别,所以没有必要为其单独抽象出一个 IPriorityObject 接口来。同时, ISamePriorityObjectManager 不要求被管理的对象继承自 IPriorityObject 接口也是为了扩大其被单独复用的范围。

IPriorityManager 接口直接从 ISamePriorityObjectManager 接口继承,说明 IPriorityManager 实际上要做工作与 ISamePriorityObjectManager 是相同的,只不过 IPriorityManager 管理的对象需要首先按优先级别进行分类,然后再使用 ISamePriorityObjectManager 管理处于同一优先级别的对象。

接下来我们看 PriorityManager 的具体实现。

PriorityManager 中,有这样的一个 约定 :优先级别是用 int 表示的,其值是从 0 开始连续的一串整数,整数值越小,表明优先级越高。当 Initialize 方法被执行后,优先等级的范围就被固定下来。比如 PriorityLevelCount 值设为 4 ,则 PriorityManager 所支持的优先等级即为: 0 1 2 3

基于这样的约定, PriorityManager 内部使用了一个 ISamePriorityObjectManager 数组,数组的索引值就对应着优先级别值。比如,数组中 index 1 ISamePriorityObjectManager 管理器中的所有对象的优先级别值都是 1

有了这两点认识,再看 PriorityManager 的源码就相当容易了,下面是其中的关键点:

(1) 在类似 AddWaiter RemoveWaiter 这样的方法实现中,都是先通过其参数对象的 PriorityLevel 属性定位到对应的 ISamePriorityObjectManager 管理器,然后再做进一步的处理的。

(2) 如果目标对象的 PriorityLevel 属性值超过了约定的范围, PriorityManager 会根据当前的情况做灵活的处理。比如,如果是调用 AddWaiter 加入一个这样的对象,则会抛出一个“不支持该优先级别”的异常;而如果是在类似 RemoveWaiter 这样的方法中,则会忽略这个对象。

(3) 如果 PriorityManager 管理器中没有任何对象时, PriorityManager GetNextWaiter 方法直接返回 null ,而不是 default(T) ,这是因为在 PriorityManager 定义的泛型约束中,要求 T 必须是一个引用类型。这就没有了前面提到的 SamePriorityObjectManager GetNextWaiter 方法的返回值可能导致的问题。

(4) GetWaitersByPriority 方法返回的对象数组具有这样的特征:优先级别越高的对象,其在数组中的位置索引就越小;同一优先级别的对象,加入时间越早的,其在数组中的位置索引越小。

4. 使用时的注意事项

(1) 如果你的系统仅仅需要按照对象的到达顺序来决定先后处理的顺序,那么直接使用 ISamePriorityObjectManager 就可以满足需求了,没有必要使用 IPriorityManager 这个更复杂的类。使用 ISamePriorityObjectManager 还有一个好处就是,被管理的对象不需要实现 IPriorityObject 接口,这样使用起来会更加方便。

(2) 如果在你的系统中不是使用 0,1,2,3… 这样的数值来表示优先级别的,那么你可以建立一个转换映射来完成优先级别值到数字的转换。并遵从 PriorityManager 所要求的约定。

(3) PriorityManager Initialize 方法一旦被调用后,其 PriorityLevelCount 属性便不应该被修改。或者说,即使该属性在之后被修改,也不会产生任何效果。

5. 扩展

优先级管理器 PriorityManager 暂时没有任何扩展。

注:ESBasic源码可到 http://esbasic.codeplex.com/ 下载。
ESBasic讨论:37677395
ESBasic开源前言

ESBasic 可复用的.NET类库(14) -- 优先级管理器 IPriorityManager


更多文章、技术交流、商务合作、联系博主

微信扫码或搜索:z360901061

微信扫一扫加我为好友

QQ号联系: 360901061

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描下面二维码支持博主2元、5元、10元、20元等您想捐的金额吧,狠狠点击下面给点支持吧,站长非常感激您!手机微信长按不能支付解决办法:请将微信支付二维码保存到相册,切换到微信,然后点击微信右上角扫一扫功能,选择支付二维码完成支付。

【本文对您有帮助就好】

您的支持是博主写作最大的动力,如果您喜欢我的文章,感觉我的文章对您有帮助,请用微信扫描上面二维码支持博主2元、5元、10元、自定义金额等您想捐的金额吧,站长会非常 感谢您的哦!!!

发表我的评论
最新评论 总共0条评论