`
soboer
  • 浏览: 1311793 次
文章分类
社区版块
存档分类
最新评论

ESBasic 可复用的.NET类库(21) -- 片段整合提取器 ScatteredSegmentPicker

 
阅读更多

1.缘起:

当数据源中的数据量多到一定程度时,我们在查询时就经常使用分页策略。如果数据源是一个完整的整体,这没有什么大不了的,我们经常就在做类似的事情。但是,如果数据源不是一个完整的整体,而是由很多有序的片段构成的,并且不同的片段可能位于不同的位置(比如,位于不同的服务器节点上的内存中),甚至,每个片段内的数据还会随着时间的变化而变化的。

在这种假设的情况下,来从这个“虚拟的完整”数据源获取某个分页就不再是那么简单的事情了。一个分页可能位于一个片段的内部的某个区间,也有可能会跨越多个片段。

我们举个例子,以更形象地说明上面描述的问题。

假设,我们有如下几个包含整数的有序片段:

片段A2358

片段B33344551567886

片段C91214151823

片段D909297108127

ABCD四个片段,每个片段内部包含的元素的个数都不一样,每个片段内部的整数都是有序的。我们还发现,任意两个片段的取值区间是没有交集的,如我们可以认为A的区间为[2,8]B的区间为[33,86] C的区间为[9,23]D的区间为[90,127]。由于任意两个片段的取值区间没有交集,所以,我们可以对这些片段的取值区间进行排序,排序的结果是:ACBD

现在我们把排序后的ACBD四个片段作为一个虚拟的整体数据源,然后对其进行分页。假设PageSize5,如果从小到大取第二页的数据应该是:1214151823;如果从大到小取第二页的数据应该是:8678565145

你也许会想,这个很容易啊,我把所有片段中的数据取出来,按顺序排列好:

23589121415182333344551567886909297108127

现在想取第几页就可以直接取第几页了,问题解决。是吗?记得我们前面还有一个假设的需求在这里没有考虑进来,那就是每个片段内的数据还会随着时间的变化而变化的,当然,约定好的取值区间是不会变化的。比如,B片段的数据在下一时刻增加了几个数据变成这样:

片段B333440424550515662788386

片段B增加的数据都是属于其取值区间[33,86]的,所以B的取值区间并不会发生变化。

上面提到的把每个片段中的所有的数据都提取出来排列好的方法就不好用了吧,因为每查询某分页一次,就需要重新排序一次。如果我们的片段非常多,而且每个片段中的数据也非常多,那么,其效率可想而知。

我设计了ESBasic.ObjectManagement.Integration.ScatteredSegmentPicker片段整合提取器来解决类似的问题。

2.适用场合:

当满足以下条件时,你可以使用ScatteredSegmentPicker来对数据源进行分页操作。

(1)数据源由多个片段(Segment)组成。

(2)每个片段内部的数据都是有序的。

(3)任意两个片段的取值区间的交集为空。

(4)片段内的数据可能发生变化,但是其最初预定的取值区间一直是恒定的。

(5)每个片段都有唯一的ID来标志它。

(6)需要从小到大的顺序或从大到小的顺序对所有片段中的数据作为一个整体进行分页。

3.设计思想与实现

根据上述的描述看到,片段是一个核心概念,我们使用ISegment接口来抽象它,ISegment定义如下:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> ///<summary>
///ISegment片段,一个片段有有序的多个元素TVal构成。
///</summary>
///<typeparamname="TSegmentID">片段标志的类型</typeparam>
///<typeparamname="TVal">构成片段的元素的类型</typeparam>
publicinterfaceISegment<TSegmentID,TVal>
{
///<summary>
///ID每个片段的唯一标志。
///</summary>
TSegmentIDID{get;}

///<summary>
///GetContent获取片段中的所有元素,从小到大排列。
///</summary>
IList<TVal>GetContent();
}

该接口有两个泛型参数:TSegmentID TValTSegmentID是片段ID的类型,TVal是片段中包含的元素的类型。GetContent方法返回片段中所有元素的列表,并且这个列表中的元素是从小到大的顺序排列的。

我们设计ISegmentContainer接口来提供所有的片段访问,ISegmentContainer接口定义如下:

<!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--> ///<summary>
///ISegmentContainer用于存放片段ISegment的容器。
///</summary>
///<typeparamname="TSegmentID">片段标志的类型</typeparam>
///<typeparamname="TVal">构成片段的元素的类型</typeparam>
publicinterfaceISegmentContainer<TSegmentID,TVal>
{
ISegment<TSegmentID,TVal>GetSmallestSegment();
ISegment<TSegmentID,TVal>GetBiggestSegment();

///<summary>
///GetNextSegment按照fromSmallToBig指定的顺序返回下一个Segment。
///如果返回null,则表示不再有后续的Segment了。
///</summary>
ISegment<TSegmentID,TVal>GetNextSegment(TSegmentIDcurSegmentID,boolfromSmallToBig);
}

这个接口也有两个与ISegment一样的泛型参数,GetSmallestSegment方法和GetBiggestSegment方法用于返回取值区间最小和最大的片段。

GetNextSegment方法的设计我们知道,ISegmentContainer不是一下子返回所有的片段列表,而是根据当前使用的片段的ID返回下一个片段。之所以这样做,是因为我们一次性获取所有片段列表的代价可能是巨大的,所以一次只返回一个必需的片段。fromSmallToBig参数的值取决于我们是按降序分页还是按升序分页。

如果不再有后续分页,GetNextSegment方法将返回null

在做了上述这些铺垫后,接下来我们来看本节真正的主角:ScatteredSegmentPicker,正是它将所有的片段整合为一个虚拟的完整数据源,然后对其进行分页提取。

ScatteredSegmentPicker类图如下所示:

  PickFromSmallToBig属性表明是要按升序还是降序来提取分页数据。Pick方法执行真正的分页提取动作,startIndex参数是指要以哪条记录作为分页的起始,pickCount参数表示要提取多少条记录,即分页的大小。

Pick方法之所以传递startIndex参数和pickCount参数,而不是传递pageSizepageIndex,是为了更灵活地支持从任意位置开始的连续记录的提取,而且,这也兼容了分页的提取。比如,你将pageSize*pageIndex作为startIndex参数传入,将pageSize作为pickCount参数传入即是一个标准的分页获取动作。

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

(1)虽然ScatteredSegmentPicker内部实现没有使用到任何加锁机制,但是它可以被使用在多线程的环境中。

(2)ScatteredSegmentPickerDoPick方法采用遍历策略来提取目标页的数据,PickFromSmallToBig属性决定了遍历片段的方向,是从小到大还是从大到小。

(3)如果要查询的分页不存在,则将返回一个不包含任何元素的List,而不是返回null

4. 使用时的注意事项

(1)在使用ScatteredSegmentPicker之前,你必须根据你的应用的需求实现ISegment接口和ISegmentContainer接口,然后将ISegmentContainer实例的引用注入到ScatteredSegmentPicker

(2)虽然我们使用ISegmentContainer来提供所需的每个片段,但是在实现该接口时,不一定非要将所有的片段都存放在ISegmentContainer这个容器中。ISegmentContainer可以作为一个片段获取器的角色从其它地方获取某个片段。比如,某个片段可能位于另外一台服务器的内存中,ISegmentContainer可以通过Remoting的方式从那台服务器获取这个片段的数据。

(3)也许你的片段中的数据不是从小到大或从大到小的顺序,而是依据另外一个性质进行排序,比如由不重要到重要,由不急迫到急迫等,这个只需要与PickFromSmallToBig做正确映射就可以正常使用ScatteredSegmentPicker了。

5.扩展

片段整合提取器 ScatteredSegmentPicker暂时没有任何扩展。

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

分享到:
评论

相关推荐

    ESBasic 可复用的.NET类库

    本人将 zhuweisky博主的博客整理成了PDF文件,以便于脱机浏览,没有经过博主的同意就这么做 实在是不好意思^-^ 现将其资料免费下载 以示对博主的尊重 源博客地址:...

    .NET设计规范:约定、惯用法与模式.pdf

    .NET设计规范:约定、惯用法与模式,在.net环境下进行开发设计的经典之作,权威指导.

    .NET设计规范:约定、惯用法与模式(第2版)克瓦林纳 5/5

    新版根据.NET Framework 3.0和3.5的新特性做了全面更新,主要关注的是直接影响框架可编程能力的设计问题。遵守这些规范对于使用.NET Framework创建高质量的应用程序至关重要。  本书提供配套光盘,内含Designing ...

    Android异步并发类库Android-lite-go.zip

    LiteGo:「迷你」的Android异步并发类库LiteGo是一款基于Java语言的「异步并发类库」,它的核心是一枚「迷你」并发器,它可以自由地设置同一时段的最大「并发」数量,等待「排队」线程数量,还可以设置「排队策略」...

    NET应用架构设计原则、模式与实践.pdf

    NET应用架构设计原则、模式与实践.pdf NET应用架构设计原则、模式与实践.pdf

    .NET敏捷开发框架-RDIFramework.NET V5.1全新测试版本

    应用系统建立在此框架之上,采用构件式、可复用开发,节省开发成本,加快开发速度,在软件开发上更好的做到多快省。 适合低中高任意开发水平的开发者,可以开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商平台后台、...

    .NET设计规范:约定、惯用法与模式(第2版)1/5

    新版根据.NET Framework 3.0和3.5的新特性做了全面更新,主要关注的是直接影响框架可编程能力的设计问题。遵守这些规范对于使用.NET Framework创建高质量的应用程序至关重要。  本书提供配套光盘,内含Designing ...

    ADO.NET sqlserver的工具类库

    自己写的ado.net类库,已实现有关数据库操作的各种方法,子类只需提供数据库连接,即可调用,极大了实现了代码复用.这是我针对实际开发中经常需要重复开发数据库操作而提出的解决方案. 注意,该类实现的是关于sqlserver...

    NET设计规范-.NET约定、惯用法与模式.part2

    5.7.4 参数数量可变的成员 147 5.7.5 指针参数 150 5.8 小结 152 第6章 为扩展性而设计 153 6.1 扩展机制 153 6.1.1 非密封类 153 6.1.2 保护成员 155 6.1.3 事件与回调函数 156 6.1.4 虚成员 ...

    C++类库开发库参考【资料整理】

    这里收集一些著名的 C/C++ 开发库、SDK、类库、可复用类与结构代码 等信息,列举它们的介绍、参考和网站链接,为各位 C/C++ 程序员和爱好者提供检索和查阅类库的方便。 下面收集的 C/C++ 类库介绍整理来源于文章:...

    免积分C++11写的可复用的线程池类 - 开源

    博文地址:http://blog.csdn.net/csnd_ayo/article/details/72457190

    应用框架的设计与实现 .NET平台 PDF

    自从.NET推出以来,他已使用.NET帮助很多行业的用户开发了体现其商业理念的软件产品.Xin Chen是.NET和EAI方面的专家,他与Microsoft和Accenture等多家技术领先的公司合作,为它们的客户提供了优秀的解决方案....

    .NET程序设计全接触

    此外,还可以创建一个新类库实现软件复用。 • 第十章介绍.NET下的数据库支持,阐述了ADO.NET的基本概念和结构,并通过示例詊细介绍C#下Web Service数据库访问的方法。 • 第十一章将在以前的基础上介绍一个...

    asp.net知识库

    泛型技巧系列:用泛型打造可复用的抽象工厂 体验.net2.0的优雅(四):Provider、策略、控制反转和依赖注入 泛型最佳实践 asp.net 2.0下嵌套masterpage页的可视化编辑 C# 2.0与泛型 动态调用对象的属性和方法——...

    NET设计规范-.NET约定、惯用法与模式.part1

    这些规范历经.NET框架三个版本的长期开发,凝聚了数千名开发人员的经验和智慧。微软的各开发组正在使用这些规范开发下一代影响世界的软件产品。 第1章 概述 1 1.1 精心设计的框架所具备的品质 2 1.1.1 精心...

    设计模式:可复用面向对象软件的基础--详细书签版

     本书结合设计实例从面向对象的设计中精选出23个设计模式,总结了面向对象设计中最有价值的经验,并且用简洁可复用的形式表达出来。本书分类描述了一组设计良好、表达清楚的软件设计模式,这些模式在实用环境下特别...

    COM及.NET组件技术软件复用

    COM组件及.NET组件技术软件复用研究

    Android应用源码之解析word文档,过程详细,易懂,代码可直接复用-IT计算机-毕业设计.zip

    Android应用源码开发Demo,主要用于毕业设计学习。

    rdiframework.net 敏捷开发框架 V5.1打包文档资料

    应用系统建立在此框架之上,采用构件式、可复用开发,节省开发成本,加快开发速度,在软件开发上更好的做到多快省。 适合低中高任意开发水平的开发者,可以开发OA、ERP、BPM、CRM、WMS、TMS、MIS、BI、电商平台后台、...

Global site tag (gtag.js) - Google Analytics