分组对象管理器 IGroupingObjectManager--ESBasic 可复用的.NET类库(13)

1.缘起:

    假设我们的订单系统需要管理所有未处理的订单,而客人经常需要查询属于自己的未处理的订单列表。另外,可能客服人员也需要根据订单ID迅速地找到对应的未处理订单。基于第一个需求,我们就可以将未处理的订单依据客人的帐号进行分组管理。

    我设计了ESBasic.ObjectManagement.Managers.IGroupingObjectManager分组对象管理器来完成对对象进行分组管理的功能。

      分组对象管理器的形象示意图如下:   

 

2.适用场合:

当你的需求覆盖以下条件时,就非常合适使用分组对象管理器:

(1)被管理的每个对象都有唯一的ID。

(2)   被管理的对象可以依据某个标志进行分组。

(3)   经常需要根据分组标志来查询符合该标志的对象列表。

(4)经常需要向管理器中增加/移除被分组的对象。

(5)经常需要根据对象ID快速查找对应的对象。

 

3.设计思想与实现

IGroupingObjectManager的接口定义如下:

     public interface IGroupingObjectManager<TGroupKey, TObjectKey, TObject> where TObject : IGroupingObject<TGroupKey ,TObjectKey>
    {
        /// <summary>
        /// Add 如果已经存在同ID的对象,则用新对象替换旧对象。
        /// </summary>        
        void Add(TObject obj);

        void Remove(TObjectKey objectID);

        /// <summary>
        /// Clear 清除所有对象与分组。
        /// </summary>
        void Clear();

        TObject Get(TObjectKey objectID);

        int TotalObjectCount { get;}

        /// <summary>
        /// GetCountOfGroup 获取某个分组中的对象的个数。
        /// </summary>        
        int GetCountOfGroup(TGroupKey groupID);

        /// <summary>
        /// GetAllObjectsCopy 获取管理器中的所有对象列表。
        /// </summary>        
        IList<TObject> GetAllObjectsCopy();

        /// <summary>
        /// GetGroupsCopy 获取所有的分组标志列表。
        /// </summary>       
        IList<TGroupKey> GetGroupsCopy();

        /// <summary>
        /// GetObjectsCopy 获取某个分组中的所有对象的列表。
        /// </summary>        
        IList<TObject> GetObjectsCopy(TGroupKey groupID);        
    }

 

这个接口包含有三个泛型参数:TGroupKey、 TObjectKey和 TObject。

TObject是被管理的对象的类型。

TObjectKey是被管理的对象的ID的类型。

TGroupKey是对被管理的对象进行分组的标志的类型。

另外,该接口的泛型参数还有一个约束,即TObject必须从IGroupingObject接口继承,以表明自己是一个可以被分组的对象。

IGroupingObject接口很简单,其定义如下:

    public interface IGroupingObject<TGroupKey,TObjectKey>
    {
        TObjectKey ID { get; }
        TGroupKey GroupID { get; }
    }

 

     观察这个接口告诉我们,只要一个对象有唯一的ID,并且有分组的标志,那么这个对象就可以被对象分组管理器进行管理了。

     关于GroupingObjectManager的实现要注意以下几点:

(1)GroupingObjectManager使用了两个字典集合:objectDictionary 、groupDictionary。objectDictionary用于存储所有被管理的对象。groupDictionary用于管理所有的分组,而且groupDictionary的Value又是另外一个字典,用于存储属于这一分组的所有对象。

(2)GroupingObjectManager的实现是线程安全的,所以可以在多线程的环境中使用。我们对其内部的两个字典集合都进行了加锁控制。

(3)Add方法采用的也是覆盖原则――如果同Key的对象已经存在,则用新对象覆盖旧的对象。

 

4. 使用时的注意事项

当调用Remove方法删除的是某个分组中的最后一个对象时,在该对象被删除后,对应的分组将也会被删除。所以,管理器中不会存在“空”的历史分组。也就是说,GetGroupsCopy方法返回的分组标志列表中的每个分组标志在管理器中对应的分组都包含至少一个被分组对象。

 

5.扩展

       分组对象管理器IGroupingObjectManager暂时没有任何扩展。

 

注: ESBasic已经开源,点击这里下载源码。
    ESBasic开源前言

 

时间: 2024-10-27 13:54:04

分组对象管理器 IGroupingObjectManager--ESBasic 可复用的.NET类库(13)的相关文章

对象管理器 IObjectManager -- ESBasic 可复用的.NET类库(12)

1.缘起: 我们经常需要对一些动态对象进行管理,最常见的例子就是在线用户管理.当一个用户成功登陆到服务器后,我们就需要将其管理起来:当他退出后,就不再需要再管理他了.这就是所谓动态对象的含义,这些对象并不是一直需要被管理,只有当其被激活后,才需要被管理.它们总是在"激活"状态和"非激活"状态之间不断地切换. 我设计了对象管理器ESBasic.ObjectManagement.Managers.IObjectManager来管理类似的动态对象.这个类是ESBasic提

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

1.缘起:     假设我们的订单处理系统所要处理的订单是有优先级的,也就是说,不同的订单类型所要求被处理的紧迫程度不同,对那些优先级高的注单要先处理,对于优先级低的注单可稍后处理.对于处于同一优先级的订单了,就按照其到达的先后顺序进行处理.     这是一个典型的管理具有优先级的对象的需求,注单就是具有优先级(With Priority)的对象.我设计了ESBasic.ObjectManagement.Managers.IPriorityManager优先级管理器(确切地说,应该称之为"具有优

ESBasic 可复用的.NET类库(00) -- 开源前言(附下载)

自从03年正式使用.NET开发以来,已经走过了6个年头,这期间我积累了几套类库和框架,ESBasic便是其中最基础的一个类库.ESBasic是Enterprise Service Basic的缩写,虽然也简写为ESB,但是它和Enterprise Service Bus(企业服务总线)没有任何关系.ESBasic是我能够快速和高效开发应用程序的利器之一,开这个专门的blog是想将它介绍给大家,希望能对大家有所启发. ESBasic覆盖的内容包括:对象管理.插件.网络(Socket).多线程.Em

Round缓存管理器RoundCacheManager--ESBasic 可复用的.NET类库(26)

1.缘起:     在增量自动获取器章节的缘起部分,我们曾提到增量缓存,本节我们将深入探讨它以及用于管理增量缓存的管理器.我们还是以增量自动获取器章节提到的例子作为基础,并做更进一步的讨论.       OK,现在让我们开始这有趣的旅程. 首先,基于前面例子给出的上下文,我们知道IIncreaseAutoRetriever获取的增量是用于累积当天的已成交订单报表的."当天已成交报表"就是一个典型的增量缓存,每当有新的增量到来,都会累加到上面. 我们假设今天是2009.07.08,那么我

循环任务切换器 CircleTaskSwitcher -- ESBasic 可复用的.NET类库(06)

 1.缘起:     假设我的订单处理系统有这样的需求:将一天24小时分为4个时段,凌晨2:15到8:30采用A类型的处理器处理接收到的订单,8:30到14:00采用B类型的处理器,14:00到20:00采用C类型的处理器,20:00到第二天凌晨2:15采用D类型的处理器.     即我们的订单处理器需要在任一天的2:15.8:30.14:00.20:00这四个时刻发生切换,这就是一个循环切换器所要做的工作.     我设计了ESBasic.Threading.Application. ICir

对象获取器IObjectRetriever -- ESBasic 可复用的.NET类库(17)

1.缘起: ESBasic中许多管理对象的容器都用到了这个ESBasic.ObjectManagement.IObjectRetriever接口,所以单独将其提出来介绍一下. 当我们向对象容器(Container)请求某个对象时,也许目标对象还未加载到容器中,这可能是因为容器在初始化的时候就没有加载这个对象,也有可能是因为这个对象是容器初始化以后新增到数据库(当然也有可能是其它的持久化存储)的.在这种情况下,对象容器就可以借助IObjectRetriever来将目标对象从数据库等持久化存储中加载

工作者引擎 IWorkerEngine -- ESBasic 可复用的.NET类库(05)

1.缘起:     假设我们的系统在运行的过程中,源源不断的有新的任务需要处理(比如订单处理),而且这些任务的处理是相互独立的,没有前后顺序依赖性(顺序依赖性是指,必须在任务A处理结束后才可开始B任务),那么我们就可以使用多个线程来同时处理多个任务.每个处理任务的线程称为"工作者(线程)".      我设计了ESBasic.Threading.Engines.IWorkerEngine工作者引擎,其目的就是使用多个线程来并行处理任务,提高系统的吞吐能力.       工作者引擎的形象

回调定时器ICallbackTimer --ESBasic 可复用的.NET类库(07)

 1.缘起:     举个例子也许就能够说清楚回调定时器的用途.假设我的订单系统接收各种不同类型的订单,当订单A进来时,系统根据订单的类型和其它特征进行综合判断后,决定A订单要在2秒之后被方法M1处理:接下来收到的B订单经过同样的判断后,决定要在10秒后被方法M2处理,--.这时候就可以用回调定时器来管理这些将要被延迟一定时间再执行的任务.     当然,我们可以使用定时器或前面介绍的循环引擎来实现这样的功能,只不过我们自己需要手动管理注册的定时回调任务,并且定时检查每一个未处理订单是否已经到了

双向映射 IBidirectionalMapping -- ESBasic 可复用的.NET类库(11)

1.缘起:     假设我们的用户管理系统要求用户的ID和Name都必须是唯一的,并且用户的ID和Name一经确定就不能被修改.而且管理系统经常需要根据ID来查找Name,也经常需要根据Name来查找ID.根据这样的需求,我们可以考虑使用一个Dictionary来将ID和Name缓存起来,通常ID作为Key,Name作为Value.这样便可实现通过ID查询Name的快速查找,但是,通过Name查找ID就不是那么快了,因为涉及到对Dictionary的Values做遍历的操作.那么,有可能使得通过