﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>博客园-zhuweisky</title><link>http://www.cnblogs.com/zhuweisky/</link><description>君子之行，静以修身，俭以养德。非淡泊无以明志，非宁静无以致远。ESFramework，基于.NET的通信框架。DataRabbit，数据存取框架，包括数据库访问框架、实体缓存、内存数据库。sky.zhuwei@163.com</description><language>zh-cn</language><lastBuildDate>Wed, 10 Feb 2010 09:57:51 GMT</lastBuildDate><pubDate>Wed, 10 Feb 2010 09:57:51 GMT</pubDate><ttl>60</ttl><item><title>ESBasic 可复用的.NET类库（20） －－ TopN排行榜容器 TopNOrderedContainer</title><link>http://www.cnblogs.com/zhuweisky/archive/2010/01/18/1650373.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Mon, 18 Jan 2010 02:00:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2010/01/18/1650373.html</guid><description><![CDATA[<p>阅读: 1411 评论: 3 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2010-01-18 10:00 <a href="http://www.cnblogs.com/zhuweisky/archive/2010/01/18/1650373.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">假设我们的会员管理系统有一个排行榜的功能，需要每隔一段时间就对系统中的所有会员（假设会员数有</span><span style="font-family: Verdana; font-size: 10pt">100</span><span style="font-family: Verdana; font-size: 10pt">万）的积分进行排序，然后对其中的前</span><span style="font-family: Verdana; font-size: 10pt">100</span><span style="font-family: Verdana; font-size: 10pt">名进行某些奖励。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">这是一个典型的</span><span style="font-family: Verdana; font-size: 10pt">TopN</span><span style="font-family: Verdana; font-size: 10pt">算法&#8213;&#8213;对巨大数量的对象进行排序，然后只需要取出最</span><span style="font-family: Verdana; font-size: 10pt">Top</span><span style="font-family: Verdana; font-size: 10pt">的前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">名（</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">比对象总数小很多），作为排行榜的数据。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">解决这样的问题，我们要注意一点，如果我们每次都对所有的对象进行完全排序，那无疑效率非常低下，而且非常不划算。因为我们只需要前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">名，而不是所有对象的先后顺序。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我设计了</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">ESBasic.ObjectManagement.TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">来解决排行榜算法，</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">只将资源花费在真正需要计算的地方，另外，</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">支持在运行过程中，将不断新产生的对象加入到排行榜。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp; TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">用于对巨大数量的对象进行</span><span style="font-family: Verdana; font-size: 10pt">TopN</span><span style="font-family: Verdana; font-size: 10pt">排序。其适用场合有如下特点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">需要被排序的对象的数量非常巨大（如几百万、甚至几千万）。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">对系统有价值的排序结果只有前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">名。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">远小于总的对象数量。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp; TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">的排行榜算法的思路是这样的，使用一个长度为</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">的数组，来存放最</span><span style="font-family: Verdana; font-size: 10pt">Top</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">个对象，越</span><span style="font-family: Verdana; font-size: 10pt">Top</span><span style="font-family: Verdana; font-size: 10pt">的对象其在数组中的</span><span style="font-family: Verdana; font-size: 10pt">Index</span><span style="font-family: Verdana; font-size: 10pt">就越小。这样，每次加入一个对象时：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">首先，判断当前的排行榜的最后一名是否比新加入的对象更</span><span style="font-family: Verdana; font-size: 10pt">Top</span><span style="font-family: Verdana; font-size: 10pt">，如果是则丢弃它。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">其次，看新加入的对象是否比当前排行榜的第一名更</span><span style="font-family: Verdana; font-size: 10pt">Top</span><span style="font-family: Verdana; font-size: 10pt">，如果是，则新的对象应该被放置在</span><span style="font-family: Verdana; font-size: 10pt">index</span><span style="font-family: Verdana; font-size: 10pt">为</span><span style="font-family: Verdana; font-size: 10pt">0</span><span style="font-family: Verdana; font-size: 10pt">的位置。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">否则，就采用二分查找算法为新加入的对象找到合适的位置，并调整排行榜中位于插入位置后面的对象的位置。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">当然，在具体实现的源码中，我们看到了还有一些边界条件的处理这里没描述出来。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp; TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">的类图如下所示：</span></p>
<p style="text-indent: 20.65pt"><strong><span style="font-family: Verdana; color: red; font-size: 10pt"><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_TopN.JPG" width="451" height="255" /></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我们看到</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">有一个泛型参数</span><span style="font-family: Verdana; font-size: 10pt">TObj</span><span style="font-family: Verdana; font-size: 10pt">，它是进行排序的对象的类型。</span><span style="font-family: Verdana; font-size: 10pt">TObj</span><span style="font-family: Verdana; font-size: 10pt">的泛型约束表明</span><span style="font-family: Verdana; font-size: 10pt">TObj</span><span style="font-family: Verdana; font-size: 10pt">必须实现</span><span style="font-family: Verdana; font-size: 10pt">IOrdered</span><span style="font-family: Verdana; font-size: 10pt">接口。</span><span style="font-family: Verdana; font-size: 10pt">IOrdered</span><span style="font-family: Verdana; font-size: 10pt">接口定义如下：</span></p>
<p style="text-indent: 20.65pt"><strong><span style="font-family: Verdana; color: red; font-size: 10pt">&nbsp;</p>
<div class="cnblogs_code" onclick="cnblogs_code_show('d698e0e6-d969-46ea-bf3e-23002ecd0676')">
<div id="cnblogs_code_open_d698e0e6-d969-46ea-bf3e-23002ecd0676">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IOrdered&nbsp;参与排行榜排序的对象必须实现的接口。<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;typeparam&nbsp;name="TOrderedObj"&gt;</span><span style="color: #008000">参与排行榜排序的对象的类型</span><span style="color: #808080">&lt;/typeparam&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IOrdered</span><span style="color: #000000">&lt;</span><span style="color: #000000">TOrderedObj</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;IsTopThan(</span><span style="color: #008080">TOrderedObj</span><span style="color: #000000">&nbsp;other);<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div></div></div>
<p>&nbsp;</p>
<p style="text-indent: 20.65pt"></span></strong><span style="font-family: Verdana; font-size: 10pt">关于这个接口要注意两点：</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">第一，该接口的唯一方法的名字为什么不是类似</span><span style="font-family: Verdana; font-size: 10pt">IsGreaterThan</span><span style="font-family: Verdana; font-size: 10pt">、</span><span style="font-family: Verdana; font-size: 10pt">IsSmallerThan</span><span style="font-family: Verdana; font-size: 10pt">等，而是</span><span style="font-family: Verdana; font-size: 10pt">IsTopThan</span><span style="font-family: Verdana; font-size: 10pt">？因为不同的应用有不同的需求，有的可能是要选择前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">个最大的，有的是要选择前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">个最小的，甚至有的可能选择前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">个最著名的，等等。而</span><span style="font-family: Verdana; font-size: 10pt">IsTopThan</span><span style="font-family: Verdana; font-size: 10pt">可以覆盖所有这些情况，反正都是最</span><span style="font-family: Verdana; font-size: 10pt">Top</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">个嘛。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">第二，</span><span style="font-family: Verdana; font-size: 10pt">IOrdered</span><span style="font-family: Verdana; font-size: 10pt">接口之所以使用泛型参数</span><span style="font-family: Verdana; font-size: 10pt">TOrderedObj</span><span style="font-family: Verdana; font-size: 10pt">，是为了避免派生类在实现</span><span style="font-family: Verdana; font-size: 10pt">IsTopThan</span><span style="font-family: Verdana; font-size: 10pt">方法时，需要将参数</span><span style="font-family: Verdana; font-size: 10pt">other</span><span style="font-family: Verdana; font-size: 10pt">的类型进行向下转换。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">现在我们在回到</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">，关于其实现要注意以下几点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">排行榜容器可以在多线程的环境中使用。</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">使用</span><span style="font-family: Verdana; font-size: 10pt">SmartRWLocker</span><span style="font-family: Verdana; font-size: 10pt">来对</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">方法进行同步，之所以选择读写锁而不是简单的</span><span style="font-family: Verdana; font-size: 10pt">lock</span><span style="font-family: Verdana; font-size: 10pt">，是因为使排行榜容器在应对多读</span><span style="font-family: Verdana; font-size: 10pt">/</span><span style="font-family: Verdana; font-size: 10pt">少写的状况时能支持更大的并发。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">排行榜的生成采用的是插入排序策略，排序的具体算法是二分查找排序。</span><span style="font-family: Verdana; font-size: 10pt">Adjust</span><span style="font-family: Verdana; font-size: 10pt">方法的实现就是二分查找算法的体现。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">GetTopN</span><span style="font-family: Verdana; font-size: 10pt">方法用于返回当前的排行榜的拷贝。之所以返回一个拷贝，是因为外部对返回的数组进行任何操作都不会影响到</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">的内部集合。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">为何不将</span><span style="font-family: Verdana; font-size: 10pt">TopN</span><span style="font-family: Verdana; font-size: 10pt">排序直接实现为一个静态方法？如果</span><span style="font-family: Verdana; font-size: 10pt">以静态的方式实现，那我们就没有办法继续动态的</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">新的对象进入排行榜，即使要达到这样的目的，也就只有构造新的</span><span style="font-family: Verdana; font-size: 10pt">list</span><span style="font-family: Verdana; font-size: 10pt">，再次调用</span><span style="font-family: Verdana; font-size: 10pt">static GetTopN</span><span style="font-family: Verdana; font-size: 10pt">方法，如此就浪费了前面的计算成果。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong><strong></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">如果要排序的对象的数量与</span><span style="font-family: Verdana; font-size: 10pt">TopN</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">值的差距并不大，那么使用</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">并不一定是最佳的选择，这时我们可以采用一些高效的完全排序算法对所有的对象进行排序，然后再取出前</span><span style="font-family: Verdana; font-size: 10pt">N</span><span style="font-family: Verdana; font-size: 10pt">名，可能速度会更快。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">　　当然，我们也可以使用最大最小堆的算法来实现TopN的排序，也是完全可行的。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp; TopN</span><span style="font-family: Verdana; font-size: 10pt">排行榜容器</span><span style="font-family: Verdana; font-size: 10pt">TopNOrderedContainer</span><span style="font-family: Verdana; font-size: 10pt">暂时没有任何扩展。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体">注：ESBasic源码可到</font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体">http://esbasic.codeplex.com/</font></span></a><font size="2" face="宋体">下载。<br />&nbsp;&nbsp; &nbsp;ESBasic讨论QQ群：37677395<br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体">ESBasic开源前言</font></a><font size="2" face="宋体"> </font><br /></span></span></span></span></p>
<p></span>&nbsp;</p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1650373.html?type=1" width="1" height="1" alt=""/><p>评论: 3　<a href="http://www.cnblogs.com/zhuweisky/archive/2010/01/18/1650373.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2010/01/18/1650373.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（19） －－ 热缓存 IHotCache</title><link>http://www.cnblogs.com/zhuweisky/archive/2010/01/05/1639445.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Tue, 05 Jan 2010 02:13:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2010/01/05/1639445.html</guid><description><![CDATA[<p>阅读: 1621 评论: 5 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2010-01-05 10:13 <a href="http://www.cnblogs.com/zhuweisky/archive/2010/01/05/1639445.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><span style="font-size: 14pt"></span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">假设我们有一个订单系统，现在这个系统要增加一个功能&#8213;&#8213;允许客人查核他认为有问题的订单的详细信息。当客人觉得自己的某个订单不对劲时，他首先会从订单系统查询这个订单的详细信息，然后打电话告诉我们的客服有问题的订单的编号，客服再去查核，如果属实，客服还要进一步上报，如果该订单非常重要，则可能需要更进一步上报复查等。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp; &nbsp;</span><span style="font-family: Verdana; font-size: 10pt">从这个需求我们看到，同一个订单可能会在比较短的时间内查询数次甚至数十次，所以我们可以称这个订单为&#8220;热点&#8221;订单。而其它的成千上万的订单可能在一个月内都不被查询一次。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我设计热缓存</span><strong><span style="font-family: Verdana; color: #008080; font-size: 10pt">ESBasic.ObjectManagement.Cache.</span> <span style="font-family: Verdana; color: #008080; font-size: 10pt">IHotCache</span></strong><span style="font-family: Verdana; font-size: 10pt">就是缓存类似&#8220;热点&#8221;订单的这些对象。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">热缓存的形象示意图如下：</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt"><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_IHotCache.JPG" width="580" height="343" /></span></p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">根据上述的描述，我们可以总结一下热缓存</span><span style="font-family: Verdana; font-size: 10pt">IHotCache</span><span style="font-family: Verdana; font-size: 10pt">的使用场合：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">根据我们系统的需求，目标对象群中的某些对象的&#8220;热&#8221;的程度可以明显地与其它对象区分开来。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">加载某一类型的对象到我们的系统中需要花费比较大的气力（比如加载速度很慢、加载过程很繁琐），而且一旦加载就会被经常使用。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">在指定的时间周期内不被访问的对象可以被卸载掉。如果一个&#8220;热&#8221;对象变&#8220;冷&#8221;了，那么我们就可以将其从热缓存中移除。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">当然，要被缓存的对象必须有唯一的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">IHotCache</span><span>的接口定义如下：</p>
<div class="cnblogs_code" onclick="cnblogs_code_show('ef594273-b719-490f-b599-a6c1529bf021')">
<div id="cnblogs_code_open_ef594273-b719-490f-b599-a6c1529bf021">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #808080">&nbsp;&nbsp;&nbsp; ///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IHotCache&nbsp;用于缓存那些活跃的对象，并定时删除不活跃的对象。该接口的实现必须是线程安全的。<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IHotCache</span><span style="color: #000000">&lt;</span><span style="color: #000000">TKey,&nbsp;TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">where</span><span style="color: #000000">&nbsp;TObject&nbsp;:&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;DetectSpanInSecs&nbsp;多长时间检测一次对象是否活跃，单位：秒。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;DetectSpanInSecs&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;MaxMuteSpanInMinutes&nbsp;对象最大的沉默时间（分钟）。如果一个对象在MaxMuteSpanInMinutes时间间隔内都不被访问，则将被从缓存中清除。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;如果该属性的值被设置为小于或等于0，则表示永远不会从缓存中清除。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;MaxMuteSpanInMinutes&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;MaxCachedCount&nbsp;最多缓存的对象个数。当超过此个数时，不再缓存新的对象。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;MaxCachedCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IObjectRetriever</span><span style="color: #000000">&lt;</span><span style="color: #000000">TKey,&nbsp;TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;ObjectRetriever&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Count&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;RequestCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}&nbsp;</span><span style="color: #008000">//</span><span style="color: #008000">请求次数</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">long</span><span style="color: #000000">&nbsp;HitCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}</span><span style="color: #008000">//</span><span style="color: #008000">命中的次数</span><span style="color: #008000"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">DateTime</span><span style="color: #000000">&nbsp;LastReadTime&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Initialize();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Clear();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Add(TKey&nbsp;id,&nbsp;TObject&nbsp;obj);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Remove(TKey&nbsp;id);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Get&nbsp;如果缓存中存在目标则直接返回，否则通过ObjectRetriever提取对象并缓存。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TObject&nbsp;Get(TKey&nbsp;id);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAll();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">event</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">CbSimple</span><span style="color: #000000">&nbsp;CacheContentChanged;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div></div></div>
<p>&nbsp;</p>
<p style="text-indent: 20.65pt"></span><span style="font-family: Verdana; font-size: 10pt">注意这个接口的泛型参数</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">有一个泛型约束，其表明</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">必须是一个引用类型，这表示我们不能使用热缓存来缓存那些值类型的对象。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">当你向</span><span style="font-family: Verdana; font-size: 10pt">IHotCache</span><span style="font-family: Verdana; font-size: 10pt">请求一个对象时，如果对象不在热缓存中（有可能是从来还未加载进缓存，也有可能是因为对象变&#8220;冷&#8221;后被移除缓存了），则会加载该对象到热缓存中并返回。我们是借助前面介绍的对象获取器</span><span style="font-family: Verdana; font-size: 10pt"><a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html" target="_blank"><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span></a></span><span style="font-family: Verdana; font-size: 10pt">来获取目标对象的。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp; &nbsp;</span><span style="font-family: Verdana; font-size: 10pt">热缓存会每隔一段时间检测一次缓存中的对象是否已经变&#8220;冷&#8221;&#8213;&#8213;即在</span><span style="font-family: Verdana; font-size: 10pt">MaxMuteSpanInMinutes</span><span style="font-family: Verdana; font-size: 10pt">时间段内都没有被访问过。这个定时检测就是使用循环引擎</span><span style="font-family: Verdana; font-size: 10pt"><a href="http://www.cnblogs.com/zhuweisky/archive/2009/09/01/1557792.html" target="_blank"><span style="font-family: Verdana; font-size: 10pt">AgileCycleEngine</span></a></span><span style="font-family: Verdana; font-size: 10pt">来做到的。如果一个对象已经变&#8220;冷&#8221;，则会将其移除热缓存&#8213;&#8213;热缓存只缓存那些&#8220;热&#8221;的东西，所以放&#8220;冷&#8221;了的就必须把它移除掉。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;RequestCount</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">HitCount</span><span style="font-family: Verdana; font-size: 10pt">分别表示热缓存接收到的请求对象的次数，和缓存命中的次数&#8213;&#8213;即无需</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">加载而直接从缓存中返回对象的次数。这两个属性提供一些统计数据，以反映我们当前使用热缓存的价值究竟有多大，以此我们可以判断这个地方是否真的需要使用热缓存。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">关于</span><span style="font-family: Verdana; font-size: 10pt">HotCache</span><span style="font-family: Verdana; font-size: 10pt">的具体实现，还需要注意以下几个方面：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">为了允许在多线程的环境中使用热缓存，所以</span><span style="font-family: Verdana; font-size: 10pt">HotCache</span><span style="font-family: Verdana; font-size: 10pt">必须在对内部的</span><span style="font-family: Verdana; font-size: 10pt">dictionary</span><span style="font-family: Verdana; font-size: 10pt">操作的时候进行加锁控制。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">热缓存在初始化（</span><span style="font-family: Verdana; font-size: 10pt">Initialize</span><span style="font-family: Verdana; font-size: 10pt">方法）时，启动循环引擎来定时检测缓存的每个对象的冷热程度。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">使用</span><span style="font-family: Verdana; font-size: 10pt">CachePackage</span><span style="font-family: Verdana; font-size: 10pt">类来封装每个被缓存的对象，其中主要是记录了被封装对象的最后一次访问时间。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">如果缓存中不存在目标对象、</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">也加载不到目标对象，</span><span style="font-family: Verdana; font-size: 10pt">Get</span><span style="font-family: Verdana; font-size: 10pt">方法将返回</span><span style="font-family: Verdana; font-size: 10pt">null</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">有两种方式可以将对象添加到热缓存中，一种是热缓存借助</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">自动加载对象；另一种是通过调用其</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">方法加入。如果我们已经预计到某个对象是&#8220;热&#8221;对象，那么就可以先将其</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">到热缓存中以备用。特别是，当</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">获取这个对象比较费气力时：）。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">热缓存加速了对&#8220;热&#8221;对象的访问，但是这是以占用内存为代价的。如果你的对象访问比较平均，没有凸显出特别&#8220;热&#8221;的对象，那么使用热缓存的作用就不大了。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">当你确定不会再使用某个对象时，可以立即调用</span><span style="font-family: Verdana; font-size: 10pt">Remove</span><span style="font-family: Verdana; font-size: 10pt">方法将其从热缓存中手动移除，而不是等到其变&#8220;冷&#8221;后才被热缓存自动移除。当这样的对象比较多，而且对象比较大时，这样做可以立即释放比较大的内存空间。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">如果某个对象已经被判定为无效或者已被外界修改（缓存中的对象的数据已经是老版本），则可以调用</span><span style="font-family: Verdana; font-size: 10pt">Remove</span><span style="font-family: Verdana; font-size: 10pt">方法将其从热缓存中移除。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（5）</span><span style="font-family: Verdana; font-size: 10pt">MaxMuteSpanInMinutes</span><span style="font-family: Verdana; font-size: 10pt">属性设置为多少比较合适，取决于你的具体应用，也许是</span><span style="font-family: Verdana; font-size: 10pt">10</span><span style="font-family: Verdana; font-size: 10pt">分钟，也有可能是</span><span style="font-family: Verdana; font-size: 10pt">24</span><span style="font-family: Verdana; font-size: 10pt">小时。如果这个属性和</span><span style="font-family: Verdana; font-size: 10pt">DetectSpanInSecs</span><span style="font-family: Verdana; font-size: 10pt">属性、</span><span style="font-family: Verdana; font-size: 10pt">MaxCachedCount</span><span style="font-family: Verdana; font-size: 10pt">属性能进行合理搭配设置，则可以使得热缓存的运行价值最大化。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">热缓存</span><span style="font-family: Verdana; font-size: 10pt">IHotCache</span><span style="font-family: Verdana; font-size: 10pt">暂时没有任何扩展。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体">注：ESBasic源码可到</font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体">http://esbasic.codeplex.com/</font></span></a><font size="2" face="宋体">下载。<br />&nbsp;&nbsp; &nbsp;ESBasic讨论QQ群：37677395<br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体">ESBasic开源前言</font></a><font size="2" face="宋体"> </font><br /></span></span></span></span></p>
<p></span>&nbsp;</p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1639445.html?type=1" width="1" height="1" alt=""/><p>评论: 5　<a href="http://www.cnblogs.com/zhuweisky/archive/2010/01/05/1639445.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2010/01/05/1639445.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（18） －－ 智能字典缓存 ISmartDictionaryCache</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/12/21/1629142.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Mon, 21 Dec 2009 08:38:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/12/21/1629142.html</guid><description><![CDATA[<p>阅读: 1735 评论: 4 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-12-21 16:38 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/21/1629142.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><span style="font-size: 14pt"></span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">假设我们有一个会员管理系统，需要向各方提供查询会员基础资料的功能。会员一经注册，其基础资料就将不再发生变化（如会员帐号、身份证</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">、注册时间等等）。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">基于这样的需求，我们可以将会员的基础资料&#8220;永久地&#8221;缓存在内存中，从而提升对任何一个会员基础资料的查询速度。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">我设计了</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">ESBasic.ObjectManagement.Cache.ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">来对这种性质的对象进行缓存。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp; 职能字典缓存的形象示意图如下：</span></p>
<p><span style="font-family: 宋体; font-size: 14pt"><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_ISmartDictionaryCache.JPG" width="444" height="349" /></span></p>
<p><span style="font-family: 宋体; font-size: 14pt">&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><strong><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span></strong><span style="font-family: Verdana; font-size: 10pt">在使用</span><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">之前，必须满足以下条件：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">将要被缓存的每个对象都有唯一的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">被缓存的对象一旦&#8220;出生&#8221;就是恒定不变的。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">对象永远不会被销毁，或者说即使被销毁了在缓存中仍然存在也无关紧要。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">的接口定义如下：</span><strong><span style="font-family: Verdana; color: red; font-size: 10pt"></p>
<div class="cnblogs_code" onclick="cnblogs_code_show('4357bb2b-31fb-499e-b107-2c8d5694905e')">
<div id="cnblogs_code_open_4357bb2b-31fb-499e-b107-2c8d5694905e">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">ISmartDictionaryCache</span><span style="color: #000000">&lt;</span><span style="color: #000000">Tkey&nbsp;,TVal</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IObjectRetriever</span><span style="color: #000000">&lt;</span><span style="color: #000000">Tkey,&nbsp;TVal</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;ObjectRetriever&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Count&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br /><br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Initialize();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Get&nbsp;如果缓存中不存在id对应的object，则采用ObjectRetriever提取一次，如果仍然提取不到则返回null。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TVal&nbsp;Get(Tkey&nbsp;id);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Clear();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;HaveContained&nbsp;当前容器是否已经存在目标对象。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;HaveContained(Tkey&nbsp;id);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TVal</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAllValListCopy();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">Tkey</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAllKeyListCopy();<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div></div></div>
<p>&nbsp;</p>
<p style="text-indent: 20.65pt"></span></strong><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">依赖于我们前面介绍的</span><span style="font-family: Verdana; font-size: 10pt"><a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html" target="_blank"><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span></a></span><span style="font-family: Verdana; font-size: 10pt">接口，这就表示智能字典缓存是通过</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">来将对象加载到缓存中来的。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Initialize</span><span style="font-family: Verdana; font-size: 10pt">方法执行时，会将所有对象都加载到内存中。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">当外部调用</span><span style="font-family: Verdana; font-size: 10pt">Get</span><span style="font-family: Verdana; font-size: 10pt">方法时，如果目标对象在缓存中不存在，缓存则会调用</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">加载目标对象。如果目标对象在持久化存储中都不存在，就会返回</span><span style="font-family: Verdana; font-size: 10pt">null</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">注意，</span><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">并没有提供任何将对象移除缓存的方法，这表明对象一旦加载到缓存中，就将一直存在直到系统停止运行。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">接口的实现是简单的。同样的，</span><span style="font-family: Verdana; font-size: 10pt">SmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">可以在多线程的环境中使用，因为我们在实现时对内部集合</span><span style="font-family: Verdana; font-size: 10pt">ditionary</span><span style="font-family: Verdana; font-size: 10pt">进行了加锁控制。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">在使用智能字典缓存时，要考虑到对象的数量和对象的尺寸大小的问题。因为如果对象的数量巨大，而且对象的个头也很大，那将占用很多的内存空间。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">如果缓存中的对象被访问的概率不是一样的，而是由明显的差别，比如有绝大部分对象从来不被访问，有的对象被密集访问，那这个时候可以考虑使用我们后面即将介绍的&#8220;热缓存&#8221;</span><span style="font-family: Verdana; font-size: 10pt">IHotCache</span><span style="font-family: Verdana; font-size: 10pt">来代替智能字典缓存。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">智能字典缓存在初始化时调用了</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">接口的</span><span style="font-family: Verdana; font-size: 10pt">RetrieveAll</span><span style="font-family: Verdana; font-size: 10pt">方法，但是正如我们在介绍</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">时提到的，在实现</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">接口的</span><span style="font-family: Verdana; font-size: 10pt">RetrieveAll</span><span style="font-family: Verdana; font-size: 10pt">方法，不一定要真正的返回所有的对象，你可以只返回那些你认为将会被使用到的对象。甚至，你可以返回一个不包含任何元素的集合，这样，智能字典缓存就只会缓存那些至少被访问过一次的对象了。在某些系统中，这也许可以有效地节省一些内存空间。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">智能字典缓存</span><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">只能缓存恒定不变的对象？嗯，这一点是千真万确的。但是，有些情况我们可以灵活处理。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">还是以我们在缘起部分提到的那个例子继续讲解，让我们在其基础上，再假设一个会员（</span><span style="font-family: Verdana; font-size: 10pt">Member</span><span style="font-family: Verdana; font-size: 10pt">）的绝大部分资料是在注册时就确定下来不会发生改变的，但是有小部分资料（比如对应这数据库中</span><span style="font-family: Verdana; font-size: 10pt">Member</span><span style="font-family: Verdana; font-size: 10pt">表中的几个列）是会发生变化的，比如会员的额度、密码、最后一次访问时间等这样的信息。当外部向系统请求这些非恒定信息时，我们就无法从智能字典缓存中获取了，因为智能字典缓存中的目标会员的这些字段可能已经不是正确的值了。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">基于这样的情况，我们仍然是可以使用智能字典缓存的。这里我提出一个</span><span style="font-family: Verdana; font-size: 10pt">SubObject</span><span style="font-family: Verdana; font-size: 10pt">（&#8220;子对象&#8221;）的概念。所谓&#8220;子对象&#8221;就是由某对象的一部分属性构成的一个新的对象。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">所以，我们可以将</span><span style="font-family: Verdana; font-size: 10pt">Member</span><span style="font-family: Verdana; font-size: 10pt">中恒定不变的部分抽出来形成一个子对象，如</span><span style="font-family: Verdana; font-size: 10pt">SubMember</span><span style="font-family: Verdana; font-size: 10pt">，那么</span><span style="font-family: Verdana; font-size: 10pt">SubMember</span><span style="font-family: Verdana; font-size: 10pt">就符合了使用</span><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">进行缓存条件。当外部要查询会员的基础资料属于恒定部分时，我们就可以非常快速地从</span><span style="font-family: Verdana; font-size: 10pt">ISmartDictionaryCache</span><span style="font-family: Verdana; font-size: 10pt">获取返回。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">对于像</span><span style="font-family: Verdana; font-size: 10pt">Member</span><span style="font-family: Verdana; font-size: 10pt">这样由恒定部分和非恒定部分构成的对象来说，除了使用这种方式进行缓存之外，还有其它的办法。但由于超出了本节的主题，我们会在其它小节进行介绍。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体">注：ESBasic源码可到</font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体">http://esbasic.codeplex.com/</font></span></a><font size="2" face="宋体">下载。<br />&nbsp;&nbsp; &nbsp;ESBasic讨论QQ群：37677395<br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体">ESBasic开源前言</font></a><font size="2" face="宋体"> </font><br /></span></span></span></span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p></span>&nbsp;</p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1629142.html?type=1" width="1" height="1" alt=""/><p>评论: 4　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/21/1629142.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/21/1629142.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（17） －－ 对象获取器IObjectRetriever</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Thu, 10 Dec 2009 01:12:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html</guid><description><![CDATA[<p>阅读: 1274 评论: 0 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-12-10 09:12 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><span style="font-size: 14pt"></span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">ESBasic</span><span style="font-family: Verdana; font-size: 10pt">中许多管理对象的容器都用到了这个ESBasic.ObjectManagement.</span><span style="font-family: Verdana; color: #008080; font-size: 10pt"><strong>IObjectRetriever</strong></span><span style="font-family: Verdana; font-size: 10pt">接口，所以单独将其提出来介绍一下。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">当我们向对象容器（</span><span style="font-family: Verdana; font-size: 10pt">Container</span><span style="font-family: Verdana; font-size: 10pt">）请求某个对象时，也许目标对象还未加载到容器中，这可能是因为容器在初始化的时候就没有加载这个对象，也有可能是因为这个对象是容器初始化以后新增到数据库（当然也有可能是其它的持久化存储）的。在这种情况下，对象容器就可以借助</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">来将目标对象从数据库等持久化存储中加载到容器中来。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">通过</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">接口，我们就将对象的加载与对象的管理两种不同的职能区分开来了。对象的加载往往是与具体的应用密切相关的，而对象的管理功能却可以被大规模复用。不同的应用只要实现</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">接口，然后将其注入到要复用的对象容器中，就可以使用</span><span style="font-family: Verdana; font-size: 10pt">ESBasic</span><span style="font-family: Verdana; font-size: 10pt">提供的那些有用的对象管理容器了。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">　　对象获取器与其它组件协作时的形象示意图如下：</span></p><span style="font-family: Verdana; font-size: 10pt"></span>
<p><span style="font-family: Verdana; font-size: 10pt"><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_IObjectRetriever.JPG" width="518" height="248" /></span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">在实现</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">接口或使用与之相关的对象管理容器时，必须满足一个条件：每个对象都有唯一的一个</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">的接口定义如下：</span>&nbsp;</p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt"></p>
<div class="cnblogs_code" onclick="cnblogs_code_show('4590584d-3348-48b1-a20c-2aa6ef2fcd1d')">
<div id="cnblogs_code_open_4590584d-3348-48b1-a20c-2aa6ef2fcd1d">
<div><!--<br/ /><br/ />Code highlighting produced by Actipro CodeHighlighter (freeware)<br/ />http://www.CodeHighlighter.com/<br/ /><br/ />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IObjectRetriever</span><span style="color: #000000">&lt;</span><span style="color: #000000">Tkey&nbsp;,TVal</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Retrieve&nbsp;根据ID获取目标对象。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TVal&nbsp;Retrieve(Tkey&nbsp;id);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;RetrieveAll&nbsp;获取所有的对象。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IDictionary</span><span style="color: #000000">&lt;</span><span style="color: #000000">Tkey,&nbsp;TVal</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;RetrieveAll();<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div></div></div>
<p>&nbsp;</p>
<p style="text-indent: 21pt">这个接口相当简单，其有两个泛型参数，</span><span style="font-family: Verdana; font-size: 10pt">TKey</span><span style="font-family: Verdana; font-size: 10pt">表示的是对象</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">的类型，</span><span style="font-family: Verdana; font-size: 10pt">TVal</span><span style="font-family: Verdana; font-size: 10pt">就是对象自身的类型。而其中的两个方法，一个是根据</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">从持久化存储中提取对象，一个则是提取所有的对象。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">在实现</span><span style="font-family: Verdana; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">接口时，可以有些灵活性：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">我们不是只能从数据库获取对象，也可以从文件获取，甚至是可以从网络获取，或者从其它的服务器获取，等等。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">实现</span><span style="font-family: Verdana; font-size: 10pt">RetrieveAll</span><span style="font-family: Verdana; font-size: 10pt">方法时，不一定真的要获取所有的对象。通常，</span><span style="font-family: Verdana; font-size: 10pt">RetrieveAll</span><span style="font-family: Verdana; font-size: 10pt">方法在容器初始化时使用，这时根据你应用的需求，只需要加载初始化时够用的对象就好了，因为有些对象可能在系统运行的整个生命周期内都用不上，那就没有必要加载它。甚至，你可以返回一个不包含任何元素的字典－－如果容器在初始化时，不需要加载任何对象的话。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">　　 另外，还有一个你需要考虑的是对象的数量，如果对象的数量巨大，而且全部都需要在初始化时加载到容器中，则可能导致初始化要很长的时间，而且也要占用很大的内存。所以，只加载那些真正需要用到的对象，即可加快初始化速度，也可以节省内存。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">在设计和实现多叉树（</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.ObjectManagement.Trees.Multiple.</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">IMultiTree</span><span style="font-family: Verdana; font-size: 10pt">）时，我借助了</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">IAgileNodePicker</span><span style="font-family: Verdana; font-size: 10pt">来提取多叉树中还未加载的节点。</span><span style="font-family: Verdana; font-size: 10pt">IAgileNodePicker</span><span style="font-family: Verdana; font-size: 10pt">继承自</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">IObjectRetriever</span><span style="font-family: Verdana; font-size: 10pt">，并添加了一个获取多叉树根节点的</span><span style="font-family: Verdana; font-size: 10pt">PickupRoot</span><span style="font-family: Verdana; font-size: 10pt">方法。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">在介绍多叉树的章节，我们会再详细介绍</span><span style="font-family: Verdana; font-size: 10pt">IAgileNodePicker</span><span style="font-family: Verdana; font-size: 10pt">这个接口。</span></p>
<p>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体">注：ESBasic源码可到</font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体">http://esbasic.codeplex.com/</font></span></a><font size="2" face="宋体">下载。<br />&nbsp;&nbsp; &nbsp;ESBasic讨论QQ群：37677395<br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体">ESBasic开源前言</font></a><font size="2" face="宋体"> </font><br /></span></span></span></p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1620808.html?type=1" width="1" height="1" alt=""/><p>评论: 0　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/12/10/1620808.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（16） －－ 定时刷新缓存管理器 IRefreshableCacheManager</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/11/21/1607429.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Sat, 21 Nov 2009 02:09:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/11/21/1607429.html</guid><description><![CDATA[<p>阅读: 1560 评论: 4 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-11-21 10:09 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/21/1607429.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">为了提升系统的性能或减轻数据库的压力等原因，我们经常在系统中使用缓存来把那些经常使用的数据保留在内存中。如果因为某些原因，缓存中这些经常使用的数据不能及时与数据源进行同步更新，那么采用定时刷新缓存中的数据有可能就是一种合适的选择。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">如果你的缓存是定时刷新，那么你就需要自己为其维护一个定时器或循环引擎。如果你的系统中像这样定时刷新的缓存有多个，而且每个缓存定时刷新的时间间隔又要求不一样，那么，使这些缓存按照你预想的情况进行运转，你就需要花费一些气力。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我设计了定时刷新缓存管理器</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">来帮助你管理你系统中所有需要进行定时刷新的缓存。它可以根据每个缓存的刷新时间间隔要求，在正确的时刻，刷新其所管理的缓存。你不用再自己手动去处理定时器或循环引擎，</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">自动为你完成这一切。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">系统中需要使用一个或多个需要进行定时刷新的缓存。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">每个缓存所要求的刷新时间间隔可能都不一样。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">刷新的时间间隔并不要求精确。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">本节所讲述的是定时刷新缓存管理器</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">，其重点在于&#8220;管理器&#8221;，而不是在于&#8220;缓存&#8221;，这点是必须清楚的。缓存只是被管理器管理的对象。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">能够被</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">管理的缓存必须是可定时刷新的缓存，也就是说，这些缓存必须实现</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCache</span><span style="font-family: Verdana; font-size: 10pt">接口以表明自己可以接受管理器的管理。</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCache</span><span>定义如下：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IRefreshableCache</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;RefreshSpanInSecs&nbsp;定时刷新的时间间隔（秒）。如果设置为0，则表示与IRefreshableCacheManager的刷新时间统一。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;RefreshSpanInSecs&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;LastRefreshTime&nbsp;最后一次刷新时间。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">DateTime&nbsp;</span><span style="color: #000000">LastRefreshTime&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Refresh();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span><span style="font-family: Verdana; font-size: 10pt">这个接口相当简单，它只要求缓存提供</span><span style="font-family: Verdana; font-size: 10pt">Refresh</span><span style="font-family: Verdana; font-size: 10pt">方法进行刷新，并通过</span><span style="font-family: Verdana; font-size: 10pt">RefreshSpanInSecs</span><span style="font-family: Verdana; font-size: 10pt">属性表示出自己希望进行定时刷新的时间间隔。<strong>如果这个属性设置为</strong></span><strong><span style="font-family: Verdana; font-size: 10pt">0</span><span style="font-family: Verdana; font-size: 10pt">（默认值），则表示该缓存接受管理器的统一调度。</span></strong></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">LastRefreshTime</span><span style="font-family: Verdana; font-size: 10pt">属性用于记录最后一次刷新结束的时间，该属性的值由管理器进行设置。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">我们从</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCache</span><span style="font-family: Verdana; font-size: 10pt">接口的定义看到，管理器不用关心与缓存中的数据相关的任何信息，这是由具体的应用在实现</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCache</span><span style="font-family: Verdana; font-size: 10pt">接口时才指定的。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">接下来，我们看看</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span>接口的定义：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IRefreshableCacheManager</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;RefreshSpanInSecs&nbsp;定时刷新缓存的时间间隔。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;RefreshSpanInSecs&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #008080">IRefreshableCache</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;CacheList&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Initialize();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;RefreshNow&nbsp;手动刷新被管理的所有缓存。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;RefreshNow();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;AddCache&nbsp;动态添加缓存。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;AddCache(</span><span style="color: #008080">IRefreshableCache&nbsp;</span><span style="color: #000000">cache);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;RemoveCache&nbsp;动态移除缓存。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;RemoveCache(</span><span style="color: #008080">IRefreshableCache&nbsp;</span><span style="color: #000000">cache);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;CacheRefreshFailed&nbsp;当某个缓存刷新抛出异常时，将触发该事件。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">event</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">CbCacheException&nbsp;</span><span style="color: #000000">CacheRefreshFailed;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span><span style="font-family: Verdana; font-size: 10pt">这个接口也有一个</span><span style="font-family: Verdana; font-size: 10pt">RefreshSpanInSecs</span><span style="font-family: Verdana; font-size: 10pt">属性，如果被管理的缓存的</span><span style="font-family: Verdana; font-size: 10pt">RefreshSpanInSecs</span><span style="font-family: Verdana; font-size: 10pt">属性设置的是</span><span style="font-family: Verdana; font-size: 10pt">0</span><span style="font-family: Verdana; font-size: 10pt">，那么管理器将用自身的这个属性对其进行调度。</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">接口的</span><span style="font-family: Verdana; font-size: 10pt">RefreshSpanInSecs</span><span style="font-family: Verdana; font-size: 10pt">属性是为了简化那种被管理的所有缓存都采用统一刷新时间间隔的情况而存在的。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;RefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">在实现时仍然是借助前面介绍的循环引擎</span><span style="font-family: Verdana; font-size: 10pt"><a href="http://www.cnblogs.com/zhuweisky/archive/2009/09/01/1557792.html" target="_blank"><span style="font-family: Verdana; font-size: 10pt">AgileCycleEngine</span></a></span><span style="font-family: Verdana; font-size: 10pt">来进行定时控制的。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">提供了</span><span style="font-family: Verdana; font-size: 10pt">AddCache</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">RemoveCache</span><span style="font-family: Verdana; font-size: 10pt">方法用于在运行中动态的添加或移除缓存。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">当某个缓存在刷新时，抛出异常，则</span><span style="font-family: Verdana; font-size: 10pt">IRefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">会触发</span><span style="font-family: Verdana; font-size: 10pt">CacheRefreshFailed</span><span style="font-family: Verdana; font-size: 10pt">事件，事件参数包含了出现异常的缓存和异常对象。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">关于</span><span style="font-family: Verdana; font-size: 10pt">RefreshableCacheManager</span><span style="font-family: Verdana; font-size: 10pt">的实现，要注意以下几点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">管理器的实现是线程安全的，可以使用于多线程的环境中。我们对其内部的缓存列表进行了加锁控制。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">管理器在初始化（</span><span style="font-family: Verdana; font-size: 10pt">Initialize</span><span style="font-family: Verdana; font-size: 10pt">）时，启动了循环引擎（其</span><span style="font-family: Verdana; font-size: 10pt">DetectSpanInSecs</span><span style="font-family: Verdana; font-size: 10pt">必须设置为</span><span style="font-family: Verdana; font-size: 10pt">1</span><span style="font-family: Verdana; font-size: 10pt">秒），而且，将所有被管理的缓存的</span><span style="font-family: Verdana; font-size: 10pt">LastRefreshTime</span><span style="font-family: Verdana; font-size: 10pt">都设置为当前时间。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">在实现</span><span style="font-family: Verdana; font-size: 10pt">EngineAction</span><span style="font-family: Verdana; font-size: 10pt">方法时，必须在</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">块中使用</span><span style="font-family: Verdana; font-size: 10pt">try</span><span style="font-family: Verdana; font-size: 10pt">来捕捉引擎刷新时抛出的异常，而不是在</span><span style="font-family: Verdana; font-size: 10pt">try</span><span style="font-family: Verdana; font-size: 10pt">块中进行</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">。这个顺序是重要的，如果在</span><span style="font-family: Verdana; font-size: 10pt">try</span><span style="font-family: Verdana; font-size: 10pt">块中进行</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">，那么当一个缓存在刷新时抛出异常而导致</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">中断后，后续缓存的刷新方法都将不会被检测和调用。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">使用锁不仅仅是为了同步对内部缓存列表集合的修改，手动调用刷新方法</span><span style="font-family: Verdana; font-size: 10pt">RefreshNow</span><span style="font-family: Verdana; font-size: 10pt">也需要被同步，否则就可能出现两个线程同时进行检测和刷新缓存的情况（一个是循环引擎的线程，另一个是手动调用</span><span style="font-family: Verdana; font-size: 10pt">RefreshNow</span><span style="font-family: Verdana; font-size: 10pt">方法的线程）。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong><strong></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">由于管理器内部实现采用了循环引擎，所以定时刷新的时间间隔不可能很精确，而且，针对每个缓存的刷新方法的顺序调用也是导致这种不精确的另一个原因。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">也由于管理器内部实现采用了循环引擎，循环引擎能设置的最小检测时间间隔为</span><span style="font-family: Verdana; font-size: 10pt">1</span><span style="font-family: Verdana; font-size: 10pt">秒，所以缓存的刷新时间间隔也不可能小于</span><span style="font-family: Verdana; font-size: 10pt">1</span><span style="font-family: Verdana; font-size: 10pt">秒。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">如果某个缓存在刷新时抛出异常，那么其</span><span style="font-family: Verdana; font-size: 10pt">LastRefreshTime</span><span style="font-family: Verdana; font-size: 10pt">属性还是记录的上一次成功刷新的时间。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">定时刷新缓存管理器通过事件暴露缓存刷新失败的通知，当缓存刷新发生异常时，我们可能需要将异常记录到日志中。如果是这样，那就可以直接使用</span><span style="font-family: Verdana; font-size: 10pt">ESBasic</span><span style="font-family: Verdana; font-size: 10pt">提供的</span><span style="font-family: Verdana; font-size: 10pt">RefreshableCacheExceptionLogBridge</span><span style="font-family: Verdana; font-size: 10pt">来完成。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RefreshableCacheExceptionLogBridge</span><span style="font-family: Verdana; font-size: 10pt">借助</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.Logger.IAgileLogger</span><span style="font-family: Verdana; font-size: 10pt">组件来将异常的详细信息记录到目标日志中。日志可以是文本文件，也可以是数据库等其他存储。</span><span style="font-family: Verdana; font-size: 10pt">ESBasic</span><span style="font-family: Verdana; font-size: 10pt">提供了</span><span style="font-family: Verdana; font-size: 10pt">IAgileLogger</span><span style="font-family: Verdana; font-size: 10pt">接口的实现</span><span style="font-family: Verdana; font-size: 10pt">FileAgileLogger</span><span style="font-family: Verdana; font-size: 10pt">，用于将日志写入文本文件中。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体">注：ESBasic源码可到</font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体">http://esbasic.codeplex.com/</font></span></a><font size="2" face="宋体">下载。<br />&nbsp;&nbsp; &nbsp;ESBasic讨论QQ群：37677395<br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体">ESBasic开源前言</font></a><font size="2" face="宋体"> </font><br /></span></span></span></p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1607429.html?type=1" width="1" height="1" alt=""/><p>评论: 4　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/21/1607429.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/21/1607429.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（15） －－ 对象池 IObjectPool</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/11/11/1600660.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Wed, 11 Nov 2009 01:43:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/11/11/1600660.html</guid><description><![CDATA[<p>阅读: 1564 评论: 1 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-11-11 09:43 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/11/1600660.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><span style="font-size: 14pt"></span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">对象池应该是一个&#8220;历史悠久&#8221;的概念了，像我们经常说的线程池、还有</span><span style="font-family: Verdana; font-size: 10pt">ADO.NET</span><span style="font-family: Verdana; font-size: 10pt">中的数据库连接池等，都属于对象池的应用。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我们的应用有时也会碰到需要使用对象池的情况，我举个例子说明一下。假设，我们需要记录某个类</span><span style="font-family: Verdana; font-size: 10pt">MyClass</span><span style="font-family: Verdana; font-size: 10pt">的每个方法每次被调用时方法执行所消耗的时间，而且，这个类是使用在多线程的环境中的，每个方法都可以同时在多个线程中执行，不需要被同步，这样可以使并发达到最大。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">好，我们可以使用</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">这个类来准确地记录每个方法的时间，关键是怎么使用它？为</span><span style="font-family: Verdana; font-size: 10pt">MyClass</span><span style="font-family: Verdana; font-size: 10pt">定义一个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">类型的成员变量，然后在每个方法的开始调用这个成员的</span><span style="font-family: Verdana; font-size: 10pt">Start</span><span style="font-family: Verdana; font-size: 10pt">以启动计时，在方法返回之前记录耗费的时间，然后</span><span style="font-family: Verdana; font-size: 10pt">Reset</span><span style="font-family: Verdana; font-size: 10pt">这个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">成员。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">这种方案只有在一种情况下可以良好工作，那就是要求对</span><span style="font-family: Verdana; font-size: 10pt">MyClass</span><span style="font-family: Verdana; font-size: 10pt">的所有方法的调用都是同步的，而且多个线程调用同一个方法时也必须被<strong>同步</strong>，否则，</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">的计时就会错乱了。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">那么如何解决了？实际上很简单，我们不需要为</span><span style="font-family: Verdana; font-size: 10pt">MyClass</span><span style="font-family: Verdana; font-size: 10pt">定义一个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">类型的成员变量，而是在每个方法的入口处，</span><span style="font-family: Verdana; font-size: 10pt">new</span><span style="font-family: Verdana; font-size: 10pt">一个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">类型的局部变量，这个局部变量只服务于当前方法的一次调用。也就是说，对</span><span style="font-family: Verdana; font-size: 10pt">MyClass</span><span style="font-family: Verdana; font-size: 10pt">的任何一个方法的任何一次调用，都会产生一个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">类型的对象专门用于这次调用的计时工作，当这次调用返回后，该</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">对象就可以被销毁了。这样就可以达到我们最初假设的需求。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">从解决方案我们看到，每次调用都会新建一个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">对象，当调用返回时，这个对象就没有存在的价值而可以被销毁了。这样的结果就是会反复地创建并销毁</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">类型的对象。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">这正是使用对象池的一个绝佳场合，我们把一些可用的</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">对象放进对象池中，每次方法被调用时，就向对象池</span><span style="font-family: Verdana; color: #ff0000; font-size: 10pt">租借</span><span style="font-family: Verdana; font-size: 10pt">一个</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">对象来进行计时，调用返回时，再将这个对象</span><span style="font-family: Verdana; color: #ff0000; font-size: 10pt">归还</span><span style="font-family: Verdana; font-size: 10pt">给对象池即可。这样就避免了</span><span style="font-family: Verdana; font-size: 10pt">Stopwatch</span><span style="font-family: Verdana; font-size: 10pt">对象的重复创建和销毁。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我设计的</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">ESBasic.ObjectManagement.Pool.IObjectPool</span><span style="font-family: Verdana; font-size: 10pt">就是一个通用的对象池，它是泛型的，所以可以池化存储不同类型的对象。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">根据我们上面的描述，我们可以总结出当有类似以下的需求时，可以使用对象池技术。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">某个类型的对象<strong>经常被重复</strong>的创建、销毁。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">每个该类型的对象被使用的时间都<strong>很短</strong>。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">使用一个共享的对象无法达到系统的要求（比如会限制最大并发量）。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">相对于新建或销毁一个对象来说，清除对象的状态要容易得多。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">IObjectPool</span><span>接口的定义如下：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IObjectPool</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">where</span><span style="color: #000000">&nbsp;TObject&nbsp;:&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;MinObjectCount&nbsp;对象池中最少同时存在的对象数。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;MinObjectCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;MaxObjectCount&nbsp;对象池中最多同时存在的对象数。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;MaxObjectCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;DetectSpanInMSecs&nbsp;当池中没有空闲的对象且数量已达到MaxObjectCount时，如果这时发生Rent调用，则检测空闲对象的时间间隔。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;默认值为10ms。&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;DetectSpanInMSecs&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;PooledObjectCreator&nbsp;用于创建池中对象的创建器。默认为DefaultPooledObjectCreator<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IPooledObjectCreator</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;PooledObjectCreator&nbsp;{&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Initialize();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TObject&nbsp;Rent();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;GiveBack(TObject&nbsp;obj);<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span>&nbsp;</p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">这个接口有一个泛型参数：</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">，表示我们要池化的对象的类型。泛型约束表明能够放入对象池中的对象必须是引用类型。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">MinObjectCount</span><span style="font-family: Verdana; font-size: 10pt">属性指示对象池在初始化的时候就必须确保池中存在的对象的数量。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">MaxObjectCount</span><span style="font-family: Verdana; font-size: 10pt">属性表示对象池最多能够容纳的对象数量。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">如果一个对象被租借出去，则对象池会将其状态标记为&#8220;繁忙&#8221;的；如果一个对象没有被租借出去或被归还，则其状况就是&#8220;空闲&#8221;的。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">对于</span><span style="font-family: Verdana; font-size: 10pt">ObjectPool</span><span style="font-family: Verdana; font-size: 10pt">的实现，要注意以下几点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">对象池是多线程安全的，可以在多线程的环境下使用。我们对内部的集合进行了加锁控制。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">对象池并不直接负责对象的创建工作，它把这项职责委托给了池化对象创建者</span><span style="font-family: Verdana; font-size: 10pt">IPooledObjectCreator</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">池化对象创建者</span><span style="font-family: Verdana; font-size: 10pt">IPooledObjectCreator</span><span style="font-family: Verdana; font-size: 10pt">不仅负责对象的创建工作，而且也负责清除对象的状态（</span><span style="font-family: Verdana; font-size: 10pt">Reset</span><span style="font-family: Verdana; font-size: 10pt">方法）。在</span><span style="font-family: Verdana; font-size: 10pt">GiveBack</span><span style="font-family: Verdana; font-size: 10pt">方法的内部就有调用</span><span style="font-family: Verdana; font-size: 10pt">Reset</span><span style="font-family: Verdana; font-size: 10pt">方法来清除对象的遗留状态的。<span style="font-family: Verdana; font-size: 10pt">IPooledObjectCreator</span>接口的定义如下所示：</span><span style="font-family: Verdana; font-size: 10pt"></p>
<div class="cnblogs_code">
<p><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #808080">&nbsp;&nbsp;&nbsp; ///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IPooledObjectCreator&nbsp;池化对象创建者。用于创建被池缓存的对象。并能清除对象的状态。</span></p>
<p><span style="color: #008000"></span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IPooledObjectCreator</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">where</span><span style="color: #000000">&nbsp;TObject&nbsp;:&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TObject&nbsp;Create();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Reset(TObject&nbsp;obj);<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></p></div>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"></span>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">当外部调用</span><span style="font-family: Verdana; font-size: 10pt">Rent</span><span style="font-family: Verdana; font-size: 10pt">方法向对象池租借一个对象时，如果对象池中没有&#8220;空闲&#8221;的对象，并且池中的对象的数量已经达到了</span><span style="font-family: Verdana; font-size: 10pt">MaxObjectCount</span><span style="font-family: Verdana; font-size: 10pt">，那么这时该如何处理了？</span><span style="font-family: Verdana; font-size: 10pt">ObjectPool</span><span style="font-family: Verdana; font-size: 10pt">采用的策略是选择等待，等待直到有对象变成&#8220;空闲&#8221;，否则就一直阻塞当前线程。你必须注意到</span><span style="font-family: Verdana; font-size: 10pt">ObjectPool</span><span style="font-family: Verdana; font-size: 10pt">采用的这个策略可能会与你的期望不一致。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">当对象池中的空闲对象很多时，即使已经远远地大于了</span><span style="font-family: Verdana; font-size: 10pt">MinObjectCount</span><span style="font-family: Verdana; font-size: 10pt">的值，对象池也不会释放其中的某些对象，而是一直保持着。</span><span style="font-family: Verdana; font-size: 10pt">MinObjectCount</span><span style="font-family: Verdana; font-size: 10pt">只是决定了池在初始化的时候应该创建的对象的数量以备用。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">基于上面的两点原因，所以我们在具体应用时需要谨慎地为</span><span style="font-family: Verdana; font-size: 10pt">MaxObjectCount</span><span style="font-family: Verdana; font-size: 10pt">设定一个合理的值。如果这个值太小，可能会使得阻塞线程的情况经常发生。当然，这个值也不是设得越大越好，因为如果平时空闲的对象很多，就表示要占用更多的资源而却没有发挥出相应的价值。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">一个从池中借出的对象在被归还回给池的时候，必须把上次使用时遗留的状态清除掉，否则后面的租借者可能会误用其遗留的状态。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（5）</span><span style="font-family: Verdana; font-size: 10pt">如果清除一个对象的状态很不容易，相反创建和销毁一个对象却非常容易，那么这时可以考虑不使用对象池，而是每次</span><span style="font-family: Verdana; font-size: 10pt">new</span><span style="font-family: Verdana; font-size: 10pt">一个对象来使用，使用完了就丢弃掉。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">如果我们要池化的对象是没有状态的，而且其类型也有不带参数的默认构造函数，那么我们可以直接使用</span><span style="font-family: Verdana; font-size: 10pt">ESBasic</span><span style="font-family: Verdana; font-size: 10pt">提供的默认池化对象创建者</span><span style="font-family: Verdana; font-size: 10pt">DefaultPooledObjectCreator</span><span style="font-family: Verdana; font-size: 10pt">。</span><span style="font-family: Verdana; font-size: 10pt">DefaultPooledObjectCreator</span><span style="font-family: Verdana; font-size: 10pt">使用反射创建对象，并且</span><span style="font-family: Verdana; font-size: 10pt">Reset</span><span style="font-family: Verdana; font-size: 10pt">方法也不对对象做任何供动作&#8213;&#8213;因为对象本身就是没有状态的，所以也就不存在清除其状态的需要了。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体"><span style="font-family: Courier">注：ESBasic源码可到</span></font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体"><span style="font-family: Courier">http://esbasic.codeplex.com/</span></font></span></a><font size="2" face="宋体"><span style="font-family: Courier">下载。</span><br /><span style="font-family: Courier">&nbsp;&nbsp;&nbsp; ESBasic讨论QQ群：37677395</span><br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体"><span style="font-family: Courier">ESBasic开源前言</span></font></a><font size="2" face="宋体"> </font></span></span></span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1600660.html?type=1" width="1" height="1" alt=""/><p>评论: 1　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/11/1600660.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/11/1600660.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（14） －－ 优先级管理器 IPriorityManager</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/11/04/1596021.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Wed, 04 Nov 2009 08:03:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/11/04/1596021.html</guid><description><![CDATA[<p>阅读: 1431 评论: 2 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-11-04 16:03 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/04/1596021.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">假设我们的订单处理系统所要处理的订单是有优先级的，也就是说，不同的订单类型所要求被处理的紧迫程度不同，对那些优先级高的注单要先处理，对于优先级低的注单可稍后处理。对于处于同一优先级的订单了，就按照其到达的先后顺序进行处理。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">这是一个典型的管理具有优先级的对象的需求，注单就是具有优先级（</span><span style="font-family: Verdana; font-size: 10pt">With Priority</span><span style="font-family: Verdana; font-size: 10pt">）的对象。我设计了</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.ObjectManagement.Managers.IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">优先级管理器（确切地说，应该称之为&#8220;具有优先级对象的管理器&#8221;）来对类似的对象进行管理。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp; 优先级管理器的形象示意图如下：</span></p>
<p><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_PriorityManager.JPG" width="587" height="339" /></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">如果你的系统需要对被管理的对象进行优先级分级，并满足以下条件，则可使用</span><span style="font-family: Verdana; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">对象需要按优先级别（</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevel</span><span style="font-family: Verdana; font-size: 10pt">）进行分类。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">优先级别的划分是固定的，不会随系统的运行而发生变化。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">对处于同一优先级别的对象，采用先来后到的顺序进行&#8220;第二优先级&#8221;的高低确定。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">优先级别可以使用</span><span style="font-family: Verdana; font-size: 10pt">&gt;=0</span><span style="font-family: Verdana; font-size: 10pt">的连续整数来表示。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">在前面的叙述中，具有优先级对象的管理器的功能职责是相当清晰明了的，在进入其实现之前，首先我们要解决的一个问题是，如何对处于同一优先级别的对象进行管理。根据前面的需求描述，如果两个对象处于相同的优先级别，则先到达的对象的优先程度（即所谓的&#8220;第二优先级&#8221;）更高。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我使用</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.ObjectManagement.Managers.</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">ISamePriorityObjectManager</span><span>（同一优先级别对象管理器）来管理属于同一优先级别的所有对象，其接口定义如下：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">&nbsp;&nbsp;&nbsp; &nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">ISamePriorityObjectManager</span><span style="color: #000000">&lt;</span><span style="color: #000000">T</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;AddWaiter&nbsp;添加一个等待者。如果等待者在管理器中已经存在，则直接返回。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;AddWaiter(T&nbsp;waiter);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Count&nbsp;当前管理器中等待者的数量。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Count&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetNextWaiter&nbsp;返回等待时间最长的waiter。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;注意，返回时并不会从等待列表中删除waiter。如果要删除某个等待者，请调用RemoveWaiter。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T&nbsp;GetNextWaiter();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetWaitersByPriority&nbsp;按照等待者加入的先后顺序返回等待者数组，数组中index越小的等待者其等待时间越长，其优先级也越高。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T[]&nbsp;GetWaitersByPriority();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;RemoveWaiter&nbsp;从管理器中移除指定的等待者。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;RemoveWaiter(T&nbsp;waiter);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Clear&nbsp;清空管理器中的所有等待者。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Clear();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Contains&nbsp;管理器中是否存在指定的等待者。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;Contains(T&nbsp;waiter);<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span><span style="font-family: Verdana; font-size: 10pt">在</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">所表述的语义环境中，被管理的对象称为&#8220;等待者&#8221;</span><span style="font-family: Verdana; font-size: 10pt">waiter</span><span style="font-family: Verdana; font-size: 10pt">&#8213;&#8213;这表示一个对象等待被处理。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">关于</span><span style="font-family: Verdana; font-size: 10pt">SamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的实现，有以下几点需要说明：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">其内部是使用</span><span style="font-family: Verdana; font-size: 10pt">LinkedList</span><span style="font-family: Verdana; font-size: 10pt">而不是</span><span style="font-family: Verdana; font-size: 10pt">Queue</span><span style="font-family: Verdana; font-size: 10pt">来存储等待者的，其主要原因在于</span><span style="font-family: Verdana; font-size: 10pt">SamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">需要支持移除管理器中任一等待者的</span><span style="font-family: Verdana; font-size: 10pt">RemoveWaiter</span><span style="font-family: Verdana; font-size: 10pt">方法。由于</span><span style="font-family: Verdana; font-size: 10pt">Queue</span><span style="font-family: Verdana; font-size: 10pt">本身不支持任意位置的删除功能，所以我使用了</span><span style="font-family: Verdana; font-size: 10pt">LinkedList</span><span style="font-family: Verdana; font-size: 10pt">。新加入的等待者将被放在</span><span style="font-family: Verdana; font-size: 10pt">LinkedList</span><span style="font-family: Verdana; font-size: 10pt">的最后位置。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">当管理器中没有任何等待者时，</span><span style="font-family: Verdana; font-size: 10pt">GetNextWaiter</span><span style="font-family: Verdana; font-size: 10pt">方法将返回</span><span style="font-family: Verdana; font-size: 10pt">default(T)</span><span style="font-family: Verdana; font-size: 10pt">，如果</span><span style="font-family: Verdana; font-size: 10pt">T</span><span style="font-family: Verdana; font-size: 10pt">是值类型，则此时</span><span style="font-family: Verdana; font-size: 10pt">GetNextWaiter</span><span style="font-family: Verdana; font-size: 10pt">返回的可能并不是一个你所期望的对象。所以，如果</span><span style="font-family: Verdana; font-size: 10pt">T</span><span style="font-family: Verdana; font-size: 10pt">是值类型，在调用</span><span style="font-family: Verdana; font-size: 10pt">GetNextWaiter</span><span style="font-family: Verdana; font-size: 10pt">之前先访问一下其</span><span style="font-family: Verdana; font-size: 10pt">Count</span><span style="font-family: Verdana; font-size: 10pt">属性确保管理器中还有等待者存在。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">SamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">使用了前面介绍的</span><span style="font-family: Verdana; font-size: 10pt"><a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/10/1580354.html" target="_blank"><span style="font-family: Verdana; font-size: 10pt">SmartRWLocker</span></a></span><span style="font-family: Verdana; font-size: 10pt">来对内部的</span><span style="font-family: Verdana; font-size: 10pt">waiterList</span><span style="font-family: Verdana; font-size: 10pt">进行读写锁控制。</span></p>
<p>&nbsp;</p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">在讨论完</span><span style="font-family: Verdana; font-size: 10pt">SamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的实现以后，我们将注意力转移到本节的主角</span><span style="font-family: Verdana; color: #008080; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">上来，</span><span style="font-family: Verdana; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">的接口定义如下：</span></p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">&nbsp;&nbsp;&nbsp; &nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IPriorityManager&nbsp;具有优先级的对象的管理器。<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;typeparam&nbsp;name="T"&gt;</span><span style="color: #008000">被管理的对象的类型，必须从IPriorityObject继承。</span><span style="color: #808080">&lt;/typeparam&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IPriorityManager</span><span style="color: #000000">&lt;</span><span style="color: #000000">T</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;:&nbsp;</span><span style="color: #008080">ISamePriorityObjectManager</span><span style="color: #000000">&lt;</span><span style="color: #000000">T</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">where</span><span style="color: #000000">&nbsp;T&nbsp;:&nbsp;</span><span style="color: #0000ff">class</span><span style="color: #000000">,&nbsp;</span><span style="color: #008080">IPriorityObject&nbsp;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;PriorityLevelCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;</span><span style="color: #0000ff">set</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">接口直接从</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">继承，并没有多加任何方法，唯一增加的就是一个</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevelCount</span><span style="font-family: Verdana; font-size: 10pt">属性和要求被管理的对象的类型必须是从</span><span style="font-family: Verdana; font-size: 10pt">IPriorityObject</span><span style="font-family: Verdana; font-size: 10pt">接口继承的一个泛型约束。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">PriorityLevelCount</span><span style="font-family: Verdana; font-size: 10pt">用于设定你的系统需要有几种优先级别。比如，我的订单基于紧急的优先级可分为紧急、普通、不紧急三种，那么就可将</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevelCount</span><span style="font-family: Verdana; font-size: 10pt">属性设置为</span><span style="font-family: Verdana; font-size: 10pt">3</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">一个类型从</span><span style="font-family: Verdana; font-size: 10pt">IPriorityObject</span><span style="font-family: Verdana; font-size: 10pt">接口继承，就表明它的实例是具有优先级属性的对象。</span><span style="font-family: Verdana; font-size: 10pt"></p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #808080">&nbsp;&nbsp;&nbsp;&nbsp;///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IPriorityObject&nbsp;具有优先级的对象的接口。<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IPriorityObject</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;PriorityLevel&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 21pt"><strong>为什么</strong></span><strong><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">没有要求被管理的对象继承自</span><span style="font-family: Verdana; font-size: 10pt">IPriorityObject</span></strong><span style="font-family: Verdana; font-size: 10pt"><strong>接口了？</strong>这是因为在</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的职责中，其仅仅是根据对象的先后顺序来确定&#8220;第二优先级&#8221;的，这并不是真正意义上的优先级别，所以没有必要为其单独抽象出一个</span><span style="font-family: Verdana; font-size: 10pt">IPriorityObject</span><span style="font-family: Verdana; font-size: 10pt">接口来。同时，</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">不要求被管理的对象继承自</span><span style="font-family: Verdana; font-size: 10pt">IPriorityObject</span><span style="font-family: Verdana; font-size: 10pt">接口也是为了扩大其被单独复用的范围。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">接口直接从</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">接口继承，说明</span><span style="font-family: Verdana; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">实际上要做工作与</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">是相同的，只不过</span><span style="font-family: Verdana; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">管理的对象需要首先按优先级别进行分类，然后再使用</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">管理处于同一优先级别的对象。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">接下来我们看</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">的具体实现。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">在</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">中，有这样的一个</span><span style="font-family: Verdana; font-size: 10pt"><strong>约定</strong>：优先级别是用</span><span style="font-family: Verdana; font-size: 10pt">int</span><span style="font-family: Verdana; font-size: 10pt">表示的，其值是从</span><span style="font-family: Verdana; font-size: 10pt">0</span><span style="font-family: Verdana; font-size: 10pt">开始连续的一串整数，整数值越小，表明优先级越高。当</span><span style="font-family: Verdana; font-size: 10pt">Initialize</span><span style="font-family: Verdana; font-size: 10pt">方法被执行后，优先等级的范围就被固定下来。比如</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevelCount</span><span style="font-family: Verdana; font-size: 10pt">值设为</span><span style="font-family: Verdana; font-size: 10pt">4</span><span style="font-family: Verdana; font-size: 10pt">，则</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">所支持的优先等级即为：</span><span style="font-family: Verdana; font-size: 10pt">0</span><span style="font-family: Verdana; font-size: 10pt">，</span><span style="font-family: Verdana; font-size: 10pt">1</span><span style="font-family: Verdana; font-size: 10pt">，</span><span style="font-family: Verdana; font-size: 10pt">2</span><span style="font-family: Verdana; font-size: 10pt">，</span><span style="font-family: Verdana; font-size: 10pt">3</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">基于这样的约定，</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">内部使用了一个</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">数组，数组的索引值就对应着优先级别值。比如，数组中</span><span style="font-family: Verdana; font-size: 10pt">index</span><span style="font-family: Verdana; font-size: 10pt">为</span><span style="font-family: Verdana; font-size: 10pt">1</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">管理器中的所有对象的优先级别值都是</span><span style="font-family: Verdana; font-size: 10pt">1</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">有了这两点认识，再看</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">的源码就相当容易了，下面是其中的关键点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">在类似</span><span style="font-family: Verdana; font-size: 10pt">AddWaiter</span><span style="font-family: Verdana; font-size: 10pt">、</span><span style="font-family: Verdana; font-size: 10pt">RemoveWaiter</span><span style="font-family: Verdana; font-size: 10pt">这样的方法实现中，都是先通过其参数对象的</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevel</span><span style="font-family: Verdana; font-size: 10pt">属性定位到对应的</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">管理器，然后再做进一步的处理的。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">如果目标对象的</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevel</span><span style="font-family: Verdana; font-size: 10pt">属性值超过了约定的范围，</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">会根据当前的情况做灵活的处理。比如，如果是调用</span><span style="font-family: Verdana; font-size: 10pt">AddWaiter</span><span style="font-family: Verdana; font-size: 10pt">加入一个这样的对象，则会抛出一个&#8220;不支持该优先级别&#8221;的异常；而如果是在类似</span><span style="font-family: Verdana; font-size: 10pt">RemoveWaiter</span><span style="font-family: Verdana; font-size: 10pt">这样的方法中，则会忽略这个对象。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">如果</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">管理器中没有任何对象时，</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">GetNextWaiter</span><span style="font-family: Verdana; font-size: 10pt">方法直接返回</span><span style="font-family: Verdana; color: #ff0000; font-size: 10pt"><strong>null</strong></span><span style="font-family: Verdana; font-size: 10pt">，而不是</span><span style="font-family: Verdana; font-size: 10pt">default(T)</span><span style="font-family: Verdana; font-size: 10pt">，这是因为在</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">定义的泛型约束中，要求</span><span style="font-family: Verdana; font-size: 10pt">T</span><span style="font-family: Verdana; font-size: 10pt">必须是一个引用类型。这就没有了前面提到的</span><span style="font-family: Verdana; font-size: 10pt">SamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">GetNextWaiter</span><span style="font-family: Verdana; font-size: 10pt">方法的返回值可能导致的问题。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">GetWaitersByPriority</span><span style="font-family: Verdana; font-size: 10pt">方法返回的对象数组具有这样的特征：优先级别越高的对象，其在数组中的位置索引就越小；同一优先级别的对象，加入时间越早的，其在数组中的位置索引越小。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong><strong></strong></p>
<p style="text-indent: -42.55pt; margin: 0cm 0cm 0pt 42.55pt"><span style="font-family: Verdana; font-size: 10pt">（1）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: Verdana; font-size: 10pt">如果你的系统仅仅需要按照对象的到达顺序来决定先后处理的顺序，那么直接使用</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">就可以满足需求了，没有必要使用</span><span style="font-family: Verdana; font-size: 10pt">IPriorityManager</span><span style="font-family: Verdana; font-size: 10pt">这个更复杂的类。使用</span><span style="font-family: Verdana; font-size: 10pt">ISamePriorityObjectManager</span><span style="font-family: Verdana; font-size: 10pt">还有一个好处就是，被管理的对象不需要实现</span><span style="font-family: Verdana; font-size: 10pt">IPriorityObject</span><span style="font-family: Verdana; font-size: 10pt">接口，这样使用起来会更加方便。</span></p>
<p style="text-indent: -42.55pt; margin: 0cm 0cm 0pt 42.55pt"><span style="font-family: Verdana; font-size: 10pt">（2）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: Verdana; font-size: 10pt">如果在你的系统中不是使用</span><span style="font-family: Verdana; font-size: 10pt">0,1,2,3&#8230;</span><span style="font-family: Verdana; font-size: 10pt">这样的数值来表示优先级别的，那么你可以建立一个转换映射来完成优先级别值到数字的转换。并遵从</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">所要求的约定。</span></p>
<p style="text-indent: -42.55pt; margin: 0cm 0cm 0pt 42.55pt"><span style="font-family: Verdana; font-size: 10pt">（3）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp;&nbsp;&nbsp; </span></span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">Initialize</span><span style="font-family: Verdana; font-size: 10pt">方法一旦被调用后，其</span><span style="font-family: Verdana; font-size: 10pt">PriorityLevelCount</span><span style="font-family: Verdana; font-size: 10pt">属性便不应该被修改。或者说，即使该属性在之后被修改，也不会产生任何效果。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">优先级管理器</span><span style="font-family: Verdana; font-size: 10pt">PriorityManager</span><span style="font-family: Verdana; font-size: 10pt">暂时没有任何扩展。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体"><span style="font-family: Courier">注：ESBasic源码可到</span></font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体"><span style="font-family: Courier">http://esbasic.codeplex.com/</span></font></span></a><font size="2" face="宋体"><span style="font-family: Courier">下载。</span><br /><span style="font-family: Courier">&nbsp;&nbsp;&nbsp; ESBasic讨论QQ群：37677395</span><br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体"><span style="font-family: Courier">ESBasic开源前言</span></font></a><font size="2" face="宋体"> </font></span></span></p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1596021.html?type=1" width="1" height="1" alt=""/><p>评论: 2　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/04/1596021.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/11/04/1596021.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（13） －－ 分组对象管理器 IGroupingObjectManager</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/10/27/1590682.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Tue, 27 Oct 2009 07:09:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/10/27/1590682.html</guid><description><![CDATA[<p>阅读: 1397 评论: 2 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-10-27 15:09 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/27/1590682.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><span style="font-size: 14pt"></span></p>
<p><span style="font-size: 14pt">&nbsp; &nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">假设我们的订单系统需要管理所有未处理的订单，而客人经常需要查询属于自己的未处理的订单列表。另外，可能客服人员也需要根据订单</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">迅速地找到对应的未处理订单。基于第一个需求，我们就可以将未处理的订单依据客人的帐号进行分组管理。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">我设计了</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.ObjectManagement.Managers.IGroupingObjectManager</span><span style="font-family: Verdana; font-size: 10pt">分组对象管理器来完成对对象进行分组管理的功能。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 分组对象管理器的形象示意图如下：</span>&nbsp;&nbsp;&nbsp; </p>
<p><img style="width: 453px; height: 684px" border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_groupingObjectManager.JPG" width="453" height="684" /></p>
<p><strong><span style="font-family: Verdana; font-size: 10pt"></span></strong>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">当你的需求覆盖以下条件时，就非常合适使用分组对象管理器：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">被管理的每个对象都有唯一的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><strong><span style="font-family: Verdana; font-size: 10pt">（2）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span></strong><strong><span style="font-family: Verdana; font-size: 10pt">被管理的对象可以依据某个标志进行分组。</span></strong><strong></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><strong><span style="font-family: Verdana; font-size: 10pt">（3）<span style="font: 7pt 'Times New Roman'">&nbsp;&nbsp; </span></span></strong><strong><span style="font-family: Verdana; font-size: 10pt">经常需要根据分组标志来查询符合该标志的对象列表。</span></strong><strong></strong></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">经常需要向管理器中增加</span><span style="font-family: Verdana; font-size: 10pt">/</span><span style="font-family: Verdana; font-size: 10pt">移除被分组的对象。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（5）</span><span style="font-family: Verdana; font-size: 10pt">经常需要根据对象</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">快速查找对应的对象。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">IGroupingObjectManager</span><span>的接口定义如下：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IGroupingObjectManager</span><span style="color: #000000">&lt;</span><span style="color: #000000">TGroupKey,&nbsp;TObjectKey,&nbsp;TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">where</span><span style="color: #000000">&nbsp;TObject&nbsp;:&nbsp;</span><span style="color: #008080">IGroupingObject</span><span style="color: #000000">&lt;</span><span style="color: #000000">TGroupKey&nbsp;,TObjectKey</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Add&nbsp;如果已经存在同ID的对象，则用新对象替换旧对象。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Add(TObject&nbsp;obj);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Remove(TObjectKey&nbsp;objectID);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Clear&nbsp;清除所有对象与分组。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Clear();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TObject&nbsp;Get(TObjectKey&nbsp;objectID);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;TotalObjectCount&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetCountOfGroup&nbsp;获取某个分组中的对象的个数。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;GetCountOfGroup(TGroupKey&nbsp;groupID);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetAllObjectsCopy&nbsp;获取管理器中的所有对象列表。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAllObjectsCopy();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetGroupsCopy&nbsp;获取所有的分组标志列表。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TGroupKey</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetGroupsCopy();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetObjectsCopy&nbsp;获取某个分组中的所有对象的列表。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetObjectsCopy(TGroupKey&nbsp;groupID);&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span>&nbsp;</p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">这个接口包含有三个泛型参数：</span><span style="font-family: Verdana; font-size: 10pt">TGroupKey</span><span style="font-family: Verdana; font-size: 10pt">、</span><span style="font-family: Verdana; font-size: 10pt"> TObjectKey</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt"> TObject</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">是被管理的对象的类型。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">TObjectKey</span><span style="font-family: Verdana; font-size: 10pt">是被管理的对象的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">的类型。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">TGroupKey</span><span style="font-family: Verdana; font-size: 10pt">是对被管理的对象进行分组的标志的类型。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">另外，该接口的泛型参数还有一个约束，即</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">必须从</span><span style="font-family: Verdana; font-size: 10pt">IGroupingObject</span><span style="font-family: Verdana; font-size: 10pt">接口继承，以表明自己是一个可以被分组的对象。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">IGroupingObject</span><span>接口很简单，其定义如下：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #0000ff">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IGroupingObject</span><span style="color: #000000">&lt;</span><span style="color: #000000">TGroupKey,TObjectKey</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TObjectKey&nbsp;ID&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TGroupKey&nbsp;GroupID&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span>&nbsp;</p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">观察这个接口告诉我们，只要一个对象有唯一的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">，并且有分组的标志，那么这个对象就可以被对象分组管理器进行管理了。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">关于</span><span style="font-family: Verdana; font-size: 10pt">GroupingObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的实现要注意以下几点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">GroupingObjectManager</span><span style="font-family: Verdana; font-size: 10pt">使用了两个字典集合：</span><span style="font-family: Verdana; font-size: 10pt">objectDictionary </span><span style="font-family: Verdana; font-size: 10pt">、</span><span style="font-family: Verdana; font-size: 10pt">groupDictionary</span><span style="font-family: Verdana; font-size: 10pt">。</span><span style="font-family: Verdana; font-size: 10pt">objectDictionary</span><span style="font-family: Verdana; font-size: 10pt">用于存储所有被管理的对象。</span><span style="font-family: Verdana; font-size: 10pt">groupDictionary</span><span style="font-family: Verdana; font-size: 10pt">用于管理所有的分组，而且</span><span style="font-family: Verdana; font-size: 10pt">groupDictionary</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">又是另外一个字典，用于存储属于这一分组的所有对象。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">GroupingObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的实现是线程安全的，所以可以在多线程的环境中使用。我们对其内部的两个字典集合都进行了加锁控制。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">方法采用的也是覆盖原则&#8213;&#8213;如果同</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">的对象已经存在，则用新对象覆盖旧的对象。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">当调用</span><span style="font-family: Verdana; font-size: 10pt">Remove</span><span style="font-family: Verdana; font-size: 10pt">方法删除的是某个分组中的最后一个对象时，在该对象被删除后，对应的分组将也会被删除。所以，管理器中不会存在&#8220;空&#8221;的历史分组。也就是说，</span><span style="font-family: Verdana; font-size: 10pt">GetGroupsCopy</span><span style="font-family: Verdana; font-size: 10pt">方法返回的分组标志列表中的每个分组标志在管理器中对应的分组都包含至少一个被分组对象。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">分组对象管理器</span><span style="font-family: Verdana; font-size: 10pt">IGroupingObjectManager</span><span style="font-family: Verdana; font-size: 10pt">暂时没有任何扩展。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体"><span style="font-family: Courier">注：ESBasic源码可到</span></font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体"><span style="font-family: Courier">http://esbasic.codeplex.com/</span></font></span></a><font size="2" face="宋体"><span style="font-family: Courier">下载。</span><br /><span style="font-family: Courier">&nbsp;&nbsp;&nbsp; ESBasic讨论QQ群：37677395</span><br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体"><span style="font-family: Courier">ESBasic开源前言</span></font></a></span></span></span></span></p>
<p>&nbsp;</p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1590682.html?type=1" width="1" height="1" alt=""/><p>评论: 2　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/27/1590682.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/27/1590682.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（12） －－ 对象管理器 IObjectManager</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/10/21/1587280.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Wed, 21 Oct 2009 01:43:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/10/21/1587280.html</guid><description><![CDATA[<p>阅读: 1982 评论: 5 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-10-21 09:43 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/21/1587280.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><span style="font-size: 14pt"></span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">我们经常需要对一些动态对象进行管理，最常见的例子就是在线用户管理。当一个用户成功登陆到服务器后，我们就需要将其管理起来；当他退出后，就不再需要再管理他了。这就是所谓动态对象的含义，这些对象并不是一直需要被管理，只有当其被激活后，才需要被管理。它们总是在&#8220;激活&#8221;状态和&#8220;非激活&#8221;状态之间不断地切换。</span></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">我设计了对象管理器</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.ObjectManagement.Managers.IObjectManager</span><span style="font-family: Verdana; font-size: 10pt">来管理类似的动态对象。这个类是</span><span style="font-family: Verdana; font-size: 10pt">ESBasic</span><span style="font-family: Verdana; font-size: 10pt">提供的众多对象管理容器中的非常简单的一个，无论是功能还是实现。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt">对象管理器的形象示意图如下：</span></p>
<p><img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_objectManager.JPG" width="436" height="293" /></p>
<p><strong><span style="font-family: Verdana; font-size: 10pt"></span></strong>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">如果你的系统有类似以下的需求，就可以使用</span><span style="font-family: Verdana; font-size: 10pt">IObjectManager</span><span style="font-family: Verdana; font-size: 10pt">：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">将要被管理的每个动态对象都有唯一的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">对象经常要被添加到管理器中和经常要从管理器中移除。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">管理器在多线程的环境下被使用。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p style="text-indent: 21pt"><span style="font-family: Verdana; font-size: 10pt">IObjectManager</span><span>的接口定义如下：</p>
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #000000">&nbsp;&nbsp;&nbsp; </span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;IObjectManager</span><span style="color: #000000">&lt;</span><span style="color: #000000">TPKey,&nbsp;TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">event</span><span style="color: #000000">&nbsp;CbGeneric</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;ObjectRegistered;<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">event</span><span style="color: #000000">&nbsp;CbGeneric</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;ObjectUnregistered;<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Count&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Add&nbsp;如果已经存在同ID的对象，则用新对象替换旧对象。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Add(TPKey&nbsp;key,&nbsp;TObject&nbsp;obj);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Remove(TPKey&nbsp;id);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Clear();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;Contains(TPKey&nbsp;id);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Get&nbsp;如果不存在，则返回default（TObject）。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TObject&nbsp;Get(TPKey&nbsp;id);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TObject</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAll();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TPKey</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetKeyList();<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">TPKey</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetKeyListByObj(TObject&nbsp;obj);<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<p style="text-indent: 20.65pt"></span><span style="font-family: Verdana; font-size: 10pt">这个接口相当简单，就像是一个</span><span style="font-family: Verdana; font-size: 10pt">IDictionary</span><span style="font-family: Verdana; font-size: 10pt">的加强版。是的，你确实可以这样理解，把</span><span style="font-family: Verdana; font-size: 10pt">IObjectManager</span><span style="font-family: Verdana; font-size: 10pt">当作一个更好用的字典。而且</span><span style="font-family: Verdana; font-size: 10pt">ObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的实现也的确是使用</span><span style="font-family: Verdana; font-size: 10pt">IDictionary</span><span style="font-family: Verdana; font-size: 10pt">来的。</span></p>
<p style="text-indent: 20.65pt"><span style="font-family: Verdana; font-size: 10pt">但是它与</span><span style="font-family: Verdana; font-size: 10pt">IDictionary</span><span style="font-family: Verdana; font-size: 10pt">的区别&#8213;&#8213;也是它更好用的地方在于：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">它是多线程安全的，可以再多线程的环境下被使用。与</span><span style="font-family: Verdana; font-size: 10pt">IDictionary</span><span style="font-family: Verdana; font-size: 10pt">相比，这应该是最大的一个易用点。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">方法采用的是覆盖原则&#8213;&#8213;如果同</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">的对象已经存在，则用新对象覆盖旧的对象。当然，如果你不想直接覆盖，再调用</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">方法之前可以先调用</span><span style="font-family: Verdana; font-size: 10pt">Contains</span><span style="font-family: Verdana; font-size: 10pt">方法检测一下。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">当调用</span><span style="font-family: Verdana; font-size: 10pt">Remove</span><span style="font-family: Verdana; font-size: 10pt">方法从管理器中移除一个不存在的对象时，并不会抛出异常，而是直接返回。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">GetKeyList</span><span style="font-family: Verdana; font-size: 10pt">方法返回的是键值的拷贝，这样在对返回列表做</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">遍历时，即使内部字典中的元素发生了增加</span><span style="font-family: Verdana; font-size: 10pt">/</span><span style="font-family: Verdana; font-size: 10pt">删除也不会影响遍历操作。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（5）</span><span style="font-family: Verdana; font-size: 10pt">当内部集合的元素发生增加</span><span style="font-family: Verdana; font-size: 10pt">/</span><span style="font-family: Verdana; font-size: 10pt">删除时，以事件（</span><span style="font-family: Verdana; font-size: 10pt">ObjectRegistered</span><span style="font-family: Verdana; font-size: 10pt">事件和</span><span style="font-family: Verdana; font-size: 10pt">ObjectUnregistered</span><span style="font-family: Verdana; font-size: 10pt">事件）的方式通知外部。</span></p>
<p style="text-indent: 20.65pt"><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span></p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IObjectManager</span><span style="font-family: Verdana; font-size: 10pt">的两个泛型参数都是没有泛型约束的，也就是说</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">可以是值类型。当</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">是值类型时，如果使用一个不存在的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">去调用</span><span style="font-family: Verdana; font-size: 10pt">Get</span><span style="font-family: Verdana; font-size: 10pt">方法，则不会返回</span><span style="font-family: Verdana; font-size: 10pt">null</span><span style="font-family: Verdana; font-size: 10pt">，因为值类型不可能为</span><span style="font-family: Verdana; font-size: 10pt">null</span><span style="font-family: Verdana; font-size: 10pt">，这时将返回</span><span style="font-family: Verdana; font-size: 10pt">default(TObject)</span><span style="font-family: Verdana; font-size: 10pt">。而这样的结果也许并不是你所期望的。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">所以，如果你的</span><span style="font-family: Verdana; font-size: 10pt">TObject</span><span style="font-family: Verdana; font-size: 10pt">为值类型，又不想出现上面的情况，那么在调用</span><span style="font-family: Verdana; font-size: 10pt">Get</span><span style="font-family: Verdana; font-size: 10pt">方法之前有必要先调用</span><span style="font-family: Verdana; font-size: 10pt">Contains</span><span style="font-family: Verdana; font-size: 10pt">方法确认一下对象是否真的存在&#8213;&#8213;这就像在使用</span><span style="font-family: Verdana; font-size: 10pt">IDictionary</span><span style="font-family: Verdana; font-size: 10pt">一样。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p>
<p><span style="font-family: 'Calibri','sans-serif'; font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">对象管理器</span><span style="font-family: Verdana; font-size: 10pt">IObjectManager</span><span style="font-family: Verdana; font-size: 10pt">暂时没有任何扩展。</span></p>
<p><span style="font-family: Verdana; font-size: 10pt"></span>&nbsp;</p>
<p><span style="font-family: Verdana; font-size: 10pt"><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体"><span style="font-family: Courier">注：ESBasic源码可到</span></font><a href="http://esbasic.codeplex.com/" target="_blank"><span style="color: #0000ff"><font size="2" face="宋体"><span style="font-family: Courier">http://esbasic.codeplex.com/</span></font></span></a><font size="2" face="宋体"><span style="font-family: Courier">下载。</span><br /><span style="font-family: Courier">&nbsp;&nbsp;&nbsp; ESBasic讨论QQ群：37677395</span><br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html" target="_blank"><font color="#000000" size="2" face="宋体"><span style="font-family: Courier">ESBasic开源前言</span></font></a></span></span></span></p><img src="http://www.cnblogs.com/zhuweisky/aggbug/1587280.html?type=1" width="1" height="1" alt=""/><p>评论: 5　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/21/1587280.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/21/1587280.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item><item><title>ESBasic 可复用的.NET类库（11） －－ 双向映射 IBidirectionalMapping</title><link>http://www.cnblogs.com/zhuweisky/archive/2009/10/15/1583723.html</link><dc:creator>zhuweisky</dc:creator><author>zhuweisky</author><pubDate>Thu, 15 Oct 2009 02:49:00 GMT</pubDate><guid>http://www.cnblogs.com/zhuweisky/archive/2009/10/15/1583723.html</guid><description><![CDATA[<p>阅读: 1655 评论: 4 作者: <a href="http://www.cnblogs.com/zhuweisky/" target="_blank">zhuweisky</a> 发表于 2009-10-15 10:49 <a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/15/1583723.html" target="_blank">原文链接</a></p><p><strong><span style="font-family: Verdana; font-size: 10pt">1.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">缘起：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="font-family: Verdana; font-size: 10pt">假设我们的用户管理系统要求用户的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">都必须是唯一的，并且用户的</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">一经确定就不能被修改。而且管理系统经常需要根据</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">来查找</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">，也经常需要根据</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">来查找</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">。根据这样的需求，我们可以考虑使用一个</span><span style="font-family: Verdana; font-size: 10pt">Dictionary</span><span style="font-family: Verdana; font-size: 10pt">来将</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">缓存起来，通常</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">作为</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">，</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">作为</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">。这样便可实现通过</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">查询</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">的快速查找，但是，通过</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">查找</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">就不是那么快了，因为涉及到对</span><span style="font-family: Verdana; font-size: 10pt">Dictionary</span><span style="font-family: Verdana; font-size: 10pt">的</span><span style="font-family: Verdana; font-size: 10pt">Values</span><span style="font-family: Verdana; font-size: 10pt">做遍历的操作。那么，有可能使得通过</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">查找</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">的速度与通过</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">查找</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">的速度一样快吗？</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">于是，我设计了</span><span style="font-family: Verdana; font-size: 10pt">ESBasic.ObjectManagement.Cache.IBidirectionalMapping</span><span style="font-family: Verdana; font-size: 10pt">（双向映射）来解决这个问题。</span></p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 双向映射的形象示意图如下：<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img border="0" alt="" src="http://images.cnblogs.com/cnblogs_com/zhuweisky/ESBasic_BidirectionalMapping.JPG" />&nbsp;</span><br /><br />
<p><strong><span style="font-family: Verdana; font-size: 10pt">2.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">适用场合：</span></strong><strong><span style="font-size: 14pt"></span></strong></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">如果满足以下的条件，则可以使用双向映射：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">是唯一的，</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">也是唯一的。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">需要对</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">做缓存。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">经常需要根据</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">来查找</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（4）</span><span style="font-family: Verdana; font-size: 10pt">经常需要根据</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">来查找</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">3</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">．设计思想与实现</span></strong><strong></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; IBidirectionalMapping</span><span style="font-family: Verdana; font-size: 10pt">接口定义如下：</span><span style="font-family: Verdana; color: red; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<div class="cnblogs_code"><!--<br /><br />Code highlighting produced by Actipro CodeHighlighter (freeware)<br />http://www.CodeHighlighter.com/<br /><br />--><span style="color: #808080">&nbsp;&nbsp;&nbsp;&nbsp;///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;IBidirectionalMapping&nbsp;双向映射。即Key和Value都是唯一的，在这种情况下使用IBidirectionalMapping可提升依据Value查找Key的速度。<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;该接口的实现必须是线程安全的。2008.08.20<br />&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">public</span><span style="color: #000000">&nbsp;</span><span style="color: #0000ff">interface</span><span style="color: #000000">&nbsp;</span><span style="color: #008080">IBidirectionalMapping</span><span style="color: #000000">&lt;</span><span style="color: #000000">T1,&nbsp;T2</span><span style="color: #000000">&gt;</span><span style="color: #000000"><br />&nbsp;&nbsp;&nbsp;&nbsp;{<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">int</span><span style="color: #000000">&nbsp;Count&nbsp;{&nbsp;</span><span style="color: #0000ff">get</span><span style="color: #000000">;&nbsp;}<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;Add&nbsp;添加映射对。如果已经有相同的key/value存在，则会覆盖。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;Add(T1&nbsp;t1,&nbsp;T2&nbsp;t2);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;RemoveByT1(T1&nbsp;t1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">void</span><span style="color: #000000">&nbsp;RemoveByT2(T2&nbsp;t2);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T1&nbsp;GetT1(T2&nbsp;t2);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T2&nbsp;GetT2(T1&nbsp;t1);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;ContainsT1(T1&nbsp;t1);<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff">bool</span><span style="color: #000000">&nbsp;ContainsT2(T2&nbsp;t2);<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetAllT1ListCopy&nbsp;返回T1类型元素列表的拷贝。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">T1</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAllT1ListCopy();<br /><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;summary&gt;</span><span style="color: #008000"><br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;GetAllT2ListCopy&nbsp;返回T2类型元素列表的拷贝。<br />&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080">///</span><span style="color: #008000">&nbsp;</span><span style="color: #808080">&lt;/summary&gt;</span><span style="color: #008000">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #808080"><br /></span><span style="color: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008080">IList</span><span style="color: #000000">&lt;</span><span style="color: #000000">T2</span><span style="color: #000000">&gt;</span><span style="color: #000000">&nbsp;GetAllT2ListCopy();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />&nbsp;&nbsp;&nbsp;&nbsp;}</span></div></p>
<p style="text-indent: 20.65pt"></span><span style="font-family: Verdana; font-size: 10pt">该接口使用了两个泛型参数，根据上面的描述，一个泛型参数表示</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">的类型，另一个泛型参数表示</span><span style="font-family: Verdana; font-size: 10pt">Vlaue</span><span style="font-family: Verdana; font-size: 10pt">的类型。由于，在双向映射中，</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">是对称的，所以我没有使用</span><span style="font-family: Verdana; font-size: 10pt">TKey</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">TValue</span><span style="font-family: Verdana; font-size: 10pt">来命名它们，而是使用</span><span style="font-family: Verdana; font-size: 10pt">T1</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">T2</span><span style="font-family: Verdana; font-size: 10pt">。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">在实现</span><span style="font-family: Verdana; font-size: 10pt">BidirectionalMapping</span><span style="font-family: Verdana; font-size: 10pt">时，我们使用两个</span><span style="font-family: Verdana; font-size: 10pt">Dictionary</span><span style="font-family: Verdana; font-size: 10pt">来完成双向映射的功能。一个</span><span style="font-family: Verdana; font-size: 10pt">Dictionary</span><span style="font-family: Verdana; font-size: 10pt">以</span><span style="font-family: Verdana; font-size: 10pt">T1</span><span style="font-family: Verdana; font-size: 10pt">为</span><span style="font-family: Verdana; font-size: 10pt">Key</span><span style="font-family: Verdana; font-size: 10pt">，</span><span style="font-family: Verdana; font-size: 10pt">T2</span><span style="font-family: Verdana; font-size: 10pt">为</span><span style="font-family: Verdana; font-size: 10pt">Value</span><span style="font-family: Verdana; font-size: 10pt">；另一个刚好反过来。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">在实现的具体过程中，要注意以下几点：</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（1）</span><span style="font-family: Verdana; font-size: 10pt">为了允许在多线程的环境中使用双向映射，所以</span><span style="font-family: Verdana; font-size: 10pt">BidirectionalMapping</span><span style="font-family: Verdana; font-size: 10pt">必须在对内部</span><span style="font-family: Verdana; font-size: 10pt">Dictionary</span><span style="font-family: Verdana; font-size: 10pt">操作的时候进行加锁控制。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（2）</span><span style="font-family: Verdana; font-size: 10pt">在实现</span><span style="font-family: Verdana; font-size: 10pt">Add</span><span style="font-family: Verdana; font-size: 10pt">方法添加一个&#8220;映射对&#8221;的时候，必须判断当前是否已经存在了相同的值，如果存在，则先删除旧的映射对，再添加新的映射对。</span></p>
<p style="text-indent: -36pt; margin: 0cm 0cm 0pt 36pt"><span style="font-family: Verdana; font-size: 10pt">（3）</span><span style="font-family: Verdana; font-size: 10pt">要注意一个细节，</span><span style="font-family: Verdana; font-size: 10pt">GetAllT1ListCopy</span><span style="font-family: Verdana; font-size: 10pt">和</span><span style="font-family: Verdana; font-size: 10pt">GetAllT2ListCopy</span><span style="font-family: Verdana; font-size: 10pt">的实现都使用了</span><span style="font-family: Verdana; font-size: 10pt">lock</span><span style="font-family: Verdana; font-size: 10pt">，这是因为在拷贝的时候会对其</span><span style="font-family: Verdana; font-size: 10pt">Keys</span><span style="font-family: Verdana; font-size: 10pt">或</span><span style="font-family: Verdana; font-size: 10pt">Values</span><span style="font-family: Verdana; font-size: 10pt">进行</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">遍历，而在对</span><span style="font-family: Verdana; font-size: 10pt">Dictionary</span><span style="font-family: Verdana; font-size: 10pt">中的元素进行</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">遍历的时候，如果同时向其中添加或删除元素，则</span><span style="font-family: Verdana; font-size: 10pt">foreach</span><span style="font-family: Verdana; font-size: 10pt">操作是会抛出异常的。</span></p>
<p>&nbsp;</p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">4. </span></strong><strong><span style="font-family: Verdana; font-size: 10pt">使用时的注意事项</span></strong></p>
<p><span style="font-family: Verdana; font-size: 10pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; BidirectionalMapping</span><span style="font-family: Verdana; font-size: 10pt">提升了通过</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">查找</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">的速度，这是通过使用了更大的内存来做到的，是典型的&#8220;空间换时间&#8221;的例子。所以，对于巨大规模的映射对的缓存，要注意内存的使用问题。</span></p>
<p><span style="font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">另外，映射对中的两个元素的类型不一定非是</span><span style="font-family: Verdana; font-size: 10pt">ID</span><span style="font-family: Verdana; font-size: 10pt">或</span><span style="font-family: Verdana; font-size: 10pt">Name</span><span style="font-family: Verdana; font-size: 10pt">这样的简单对象，实际上，非常复杂的对象也可以缓存在双向映射中，只要其</span><span style="font-family: Verdana; font-size: 10pt">GetHashCode</span><span style="font-family: Verdana; font-size: 10pt">方法实现的恰当就不会有任何问题。</span></p>
<p><strong>&nbsp;</strong></p>
<p><strong><span style="font-family: Verdana; font-size: 10pt">5.</span></strong><strong><span style="font-family: Verdana; font-size: 10pt">扩展</span></strong></p><span style="font-family: 'Calibri','sans-serif'; font-size: 14pt">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="font-family: Verdana; font-size: 10pt">双向映射</span><span style="font-family: Verdana; font-size: 10pt">BidirectionalMapping</span><span style="font-family: Verdana; font-size: 10pt">暂时没有任何扩展。<br /><br /><span style="font-size: 10pt"><span style="font-size: 10pt"><font face="宋体"><span style="font-family: Courier">注：ESBasic源码可到</span></font><a href="http://esbasic.codeplex.com/"><span style="color: #0000ff"><font size="2" face="宋体"><span style="font-family: Courier">http://esbasic.codeplex.com/</span></font></span></a><font size="2" face="宋体"><span style="font-family: Courier">下载。</span><br /><span style="font-family: Courier">&nbsp;&nbsp;&nbsp; ESBasic讨论QQ群：37677395</span><br />&nbsp;&nbsp;&nbsp;&nbsp;</font><a href="http://www.cnblogs.com/zhuweisky/archive/2009/08/25/1553374.html"><font color="#000000" size="2" face="宋体"><span style="font-family: Courier">ESBasic开源前言</span></font></a><font size="2" face="宋体"> </font></span></span></span> <img src="http://www.cnblogs.com/zhuweisky/aggbug/1583723.html?type=1" width="1" height="1" alt=""/><p>评论: 4　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/15/1583723.html#pagedcomment" target="_blank">查看评论</a>　<a href="http://www.cnblogs.com/zhuweisky/archive/2009/10/15/1583723.html#commentform" target="_blank">发表评论</a></p><hr/><p>最新新闻：<br/>· <a href="http://news.cnblogs.com/n/56859/" target="_blank">美调查公司称苹果iPad配件成本最低219美元</a><span style="color:gray">(2010-02-10 17:20)</span><br/>· <a href="http://news.cnblogs.com/n/56858/" target="_blank">摩尔庄园：儿童生意密码</a><span style="color:gray">(2010-02-10 17:15)</span><br/>· <a href="http://news.cnblogs.com/n/56857/" target="_blank">Facebook与美国在线合作 整合AIM动态功能</a><span style="color:gray">(2010-02-10 16:41)</span><br/>· <a href="http://news.cnblogs.com/n/56855/" target="_blank">NDepend 3.0已与Visual Studio集成</a><span style="color:gray">(2010-02-10 16:17)</span><br/>· <a href="http://news.cnblogs.com/n/56854/" target="_blank">Ruby in Steel 1.5发布，去除IronRuby支持</a><span style="color:gray">(2010-02-10 16:14)</span><br/></p><p>编辑推荐：<a href="http://news.cnblogs.com/news/tag/Buzz/" target="_blank">Google Buzz相关新闻</a><br/></p><p>网站导航：<a href="http://www.cnblogs.com" target="_blank">博客园首页</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/" target="_blank">个人主页</a>&nbsp;&nbsp;<a href="http://news.cnblogs.com" target="_blank">新闻</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/ing/" target="_blank">闪存</a>&nbsp;&nbsp;<a href="http://home.cnblogs.com/group/" target="_blank">小组</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com/q/" target="_blank">博问</a>&nbsp;&nbsp;<a href="http://space.cnblogs.com" target="_blank">社区</a>&nbsp;&nbsp;<a href="http://kb.cnblogs.com" target="_blank">知识库</a></p>]]></description></item></channel></rss>