﻿<?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>C++博客-清风竹林-随笔分类-design</title><link>http://www.cppblog.com/xmli/category/10371.html</link><description>ぷ雪飘绛梅映残红 &lt;br&gt;
&amp;nbsp;&amp;nbsp; ぷ花舞霜飞映苍松&lt;br&gt; &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;----- Do more,suffer less</description><language>zh-cn</language><lastBuildDate>Sat, 11 Dec 2010 01:08:52 GMT</lastBuildDate><pubDate>Sat, 11 Dec 2010 01:08:52 GMT</pubDate><ttl>60</ttl><item><title>游戏客户端与编辑器代码重用设计杂谈</title><link>http://www.cppblog.com/xmli/archive/2010/12/10/136043.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Fri, 10 Dec 2010 04:28:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2010/12/10/136043.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/136043.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2010/12/10/136043.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/136043.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/136043.html</trackback:ping><description><![CDATA[<p align="CENTER" style="margin-bottom: 0cm"><font color="#000000"><font size="4" style="font-size: 16pt"><strong><span lang="zh-CN">游戏客户端与编辑器</span>代码重<span lang="zh-CN">用</span>设计<span lang="zh-CN">杂谈</span></strong></font></font></p>
<p align="CENTER" style="margin-bottom: 0cm">版本：<font face="Times New Roman, serif">0.1</font></p>
<p align="CENTER" style="margin-bottom: 0cm">最后修改：<font face="Times New Roman, serif">2010-12-10</font></p>
<p align="CENTER" style="margin-bottom: 0cm">撰写：李现民</p>
<p align="CENTER" style="margin-bottom: 0cm"><br>
</p>
<h1 lang="zh-CN" class="cjk">引言</h1>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>很多游戏都有配套的编辑器，或通用或专用，这样可以方便策划及时设计、修改游戏数据。当一个游戏方案确认实施时，如果需要设计配套编辑器，那么它往往先于游戏本身而设计。出于代码重用和方便维护的需要，大部分核心代码会在游戏客户端与编辑器中同时使用，因此有效提取这部分共用代码并尽量减少与项目其它部分的耦合就成为设计的重点。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>关于良好程序架构设计的话题，比如设计模式、领域驱动设计等，相关论著恒河沙数。本文结合实践中遇到的问题，从工具与技术相结合的角度来阐述相关问题的解决方案。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>以下假定程序运行环境为<font face="Times New Roman, serif">VC6+XP</font>。从本文撰写时间看（<font face="Times New Roman, serif">2010-12-10</font>），<font face="Times New Roman, serif">VC6</font>无论如何都不是一个好的选择，但限于笔者所在公司环境如此，所以只好将就着来了╮<font face="Times New Roman, serif">(╯▽╰)╭</font>。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<h1 class="cjk">使用宏控制代码生成策略</h1>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>尽管我们追求代码的可重用性，但实际情况往往并不尽如人意，特别是在与特定于游戏客户端<span lang="zh-CN">（</span>或编辑器<span lang="zh-CN">）</span>的功能相结合比较紧密的<span lang="zh-CN">代码</span>部分<span lang="zh-CN">。</span>比如<font face="Times New Roman, serif">UI</font>（<span lang="zh-CN">界面</span>），游戏<span lang="zh-CN">客户端</span>中有独立的界面模块，而编辑器界面<span lang="zh-CN">可能</span>使用<font face="Times New Roman, serif">MFC</font>制作<span lang="zh-CN">。即使同一个函数接口，游戏客户端与编辑器所需要的功能也可能是不一样的，这是因为它们拥有各自不同的应用倾向：游戏客户端倾向于使游戏画质更加平滑，而编辑器则需要考虑策划人员快速的编辑修改数据；再比如游戏客户端可能需要网络</span><font face="Times New Roman, serif">IO</font><span lang="zh-CN">功能，而编辑器则一般不需要。</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">宏（具体的说，</span><font face="Times New Roman, serif">C++</font><span lang="zh-CN">中的宏），此时可能是一种比较合适的工具。比如，通过在游戏客户端与编辑器中定义不同的宏变量，可以使游戏客户端专用的网络</span><font face="Times New Roman, serif">IO</font><span lang="zh-CN">代码在编辑器中根本不生成。</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>某些情况下可能需要在<font color="#800000">同一个项目下建立多个<font face="Times New Roman, serif">configurations</font></font><font color="#800000">（配置），通过定义不同的宏变量以控制生成不同版本的程序，比如：简化版、完整版、内部版等</font>。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>宏在<font face="Times New Roman, serif">VC</font>环境中有大量的应用案例，比如<font face="Times New Roman, serif">windows.h</font>头文件中定义了大量的宏用于控制不同环境下的代码生成策略。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<h1 class="cjk"><span lang="zh-CN">使用函数控制代码生成策略并信任</span>编译器<span lang="zh-CN">优化</span></h1>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">宏控制的原理是将不需要的代码当作注释直接移除，因此编</span><font color="#800000"><span lang="zh-CN">译器不会去审查该部分代码的正确性。这在某些情况下是必须的</span></font><span lang="zh-CN">，比如编辑器没有网络</span><font face="Times New Roman, serif">IO</font><span lang="zh-CN">相关的代码接口，因此相关代码必须被清除，否则编辑器项目将无法正确编译。</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>但宏控制有自己的问题：</p>
<ol>
	<li><p lang="zh-CN" style="margin-bottom: 0cm">宏变量通常定义在<font face="Times New Roman, serif">Project
	Settings</font>（工程设置）中，因此不容易记忆或查找；</p>
	</li><li><p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">IDE</font>工具通常无法像支持代码一样支持此类宏变量的快速查找，特别是存在多个项目相互引用的复杂工程中（比如<font face="Times New Roman, serif">Visual
	Assist X</font>有<font face="Times New Roman, serif">Find
	Reference</font>功能，可以快速搜索到所有引用指定变量或函数的代码，但此功能不支持在<font face="Times New Roman, serif">Project
	Settings</font>中定义的宏变量）；</p>
	</li><li><p lang="zh-CN" style="margin-bottom: 0cm">编译器无法审查被移除部分代码的正确性，这可能导致一些代码修改同步的问题。</p></li></ol>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>针对这些问题，笔者的解决方案是：宏控制变量只使用一次，用于定义一个简单函数，而该函数返回当前宏控制变量的存在情况，其它原本使用宏控制变量的地方都改为使用这个函数判断。这样<font color="#800000">间接的将宏变量控制转换为函数控制，从而获得<font face="Times New Roman, serif">IDE</font></font><font color="#800000">工具支持与编译器代码审查的双重好处</font>。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>比如如下代码：</p>
<p style="margin-bottom: 0cm; background: #e6e6e6"><font face="Times New Roman, serif"><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">namespace</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">edition<br></span></font></font></font><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">{<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">#ifdef</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">_EDITOR<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">inline</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">bool</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">IsEditor</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">()
{ </span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">return</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">true</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;
}<br></span></font></font></span><span  style="color: rgb(0, 0, 255); font-family: 'Times New Roman', serif; font-size: 14.4px; ">#else<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">inline</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">bool</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">IsEditor</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">()
{ </span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">return</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">false</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;
}<br></span></font></font></span><span  style="color: rgb(0, 0, 255); font-family: 'Times New Roman', serif; font-size: 14.4px; ">#endif<br></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">}<br><span  style="font-size: medium; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx"><font  color="#000000"><br></font>void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Print</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">()<br></span></font></font></span></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">{<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">if</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">edition</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">::</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">IsEditor</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">())<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">{<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">puts</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#a31515"><font size="2" style="font-size: 9pt"><span lang="zxx">"This
is editor"</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">}<br></span><span  style="color: rgb(0, 0, 255); font-family: 'Times New Roman', serif; font-size: 14.4px; ">else<br></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">{<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">puts</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#a31515"><font size="2" style="font-size: 9pt"><span lang="zxx">"This
is not editor"</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">}<br></span><span  style="font-family: 'Times New Roman', serif; font-size: 14.4px; ">}</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>宏变量<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">_EDITOR</span></font></font></font>只使用一次，其余地方都使用<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">edition</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">::</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">IsEditor</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">()</span></font></font></font>区分是编辑器代码还是游戏客户端代码。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>请注意，我们并不会有任何的运行期性能损失，虽然看起来并非如此。由于在编译期<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">edition</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">::</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">IsEditor</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">()</span></font></font></font>的值是确定的，因此<font color="#800000">当打开优化时编译器会移除不可达代码，从而得到与宏控制情况下相同的可执行文件</font>。当然，在<font face="Times New Roman, serif">Debug</font>版本下（优化关闭）所有的代码都被编译生成到最终可执行文件中，但我猜您应该不会将<font face="Times New Roman, serif">Debug</font>版本给最终用户使用对吧？</p>
<p style="margin-bottom: 0cm"><br>
</p>
<h1 class="cjk">使用<font face="Times New Roman, serif">delegate</font>解耦</h1>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">在</span><font face="Times New Roman, serif">MVC</font><span lang="zh-CN">架构下，使用</span><font face="Times New Roman, serif">Observer</font><span lang="zh-CN">（观察者）模式将核心逻辑代码与</span><font face="Times New Roman, serif">UI</font><span lang="zh-CN">界面代码分离似乎天经地义的事，这样做的好处是核心逻辑代码可以独立于</span><font face="Times New Roman, serif">UI</font><span lang="zh-CN">代码而存在，从而达到重用的目的。但不幸的是，从笔者经手的代码看，很多程序员并没有注意到这一点。主要问题可能包括以下两个方面：</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>第一是核心逻辑代码与<font face="Times New Roman, serif">UI</font>界面代码相互调用关系错综复杂。由于核心逻辑代码不独立，因而很难进行提取复用。这种情况相对比较常见。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>第二个问题解释起来可能更复杂一些。由于缺乏从核心逻辑代码到<font face="Times New Roman, serif">UI</font>界面代码的回调机制，程序员可能会被迫使用一些极端的手法来达到侦测指定事件是否发生的目的。比如，我们知道游戏客户端都有一个主循环<font face="Times New Roman, serif">main_loop</font>，方法名称通常叫<font face="Times New Roman, serif">Update()</font>或<font face="Times New Roman, serif">Tick()</font>，用于更新每一帧的游戏动画。这时，程序员可能会在该循环中埋伏一些代码以侦测核心逻辑状态的变化情况，从而达到触发事件的目的。这种手法实现了功能，保持了低耦合，却降低了代码执行效率。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>这两个问题的解决之道在于观察者模式。这个模式在实现上还是比较复杂的，对每一个要处理事件都需要定义对应的观察者与被观察者接口。这种代码复杂性曾使很多人望而却步（包括本人<font face="Times New Roman, serif">-___-</font>），为此<font face="Times New Roman, serif">java</font>中内置了<font face="Times New Roman, serif">java.util.Observer</font>与<font face="Times New Roman, serif">java.util.Observable</font>接口，以降低使用该模式的代价。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">笔者建议的方案是使用</span><font face="Times New Roman, serif">delegate</font><span lang="zh-CN">（委托）。没错，就是那个</span><font face="Times New Roman, serif">C#</font><span lang="zh-CN">中的</span><font face="Times New Roman, serif">delegate</font><span lang="zh-CN">，它能够极低的设计复杂度实现与观察者模式相同的解耦效果。具体实例这里不再列举，因为网上可以找到很多。如果你使用的是</span><font face="Times New Roman, serif">C#</font><span lang="zh-CN">，那么你是幸运的；如果你使用的是</span><font face="Times New Roman, serif">C++</font><span lang="zh-CN">，那么网上同样可以找到设计好的仿真类库；如果你不幸使用了</span><font face="Times New Roman, serif">VC6</font><span lang="zh-CN">，并且实在找到出路了，那么同学你也许可以去参考一下我的另一篇文章《</span><font face="Times New Roman, serif">VC6</font><span lang="zh-CN">中简易</span><font face="Times New Roman, serif">delegate</font><span lang="zh-CN">实现》，或许会有点帮助。</span><font face="Times New Roman, serif">	</font></p>
<p style="margin-bottom: 0cm"><br>
</p>
<h1 class="cjk">结语</h1>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">本来还想加点静态变量与通用工厂的话题的，但我发现</span><font face="Times New Roman, serif">meyers
singleton</font><span lang="zh-CN">在</span><font face="Times New Roman, serif">VC6</font><span lang="zh-CN">中的某种应用模式下会问题（</span><font face="Times New Roman, serif">singleton</font><span lang="zh-CN">对象的构造函数会被调用两次，</span><font face="Times New Roman, serif">T__T</font><span lang="zh-CN">），因此先欠着账，等待下次有成熟方案的时候再说吧。不过对此问题诸位看官如果有相关宝贵经验的话不妨提携一二，感激不尽中。</span></p>
<img src ="http://www.cppblog.com/xmli/aggbug/136043.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2010-12-10 12:28 <a href="http://www.cppblog.com/xmli/archive/2010/12/10/136043.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++通用删除器设计</title><link>http://www.cppblog.com/xmli/archive/2010/11/15/133653.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Mon, 15 Nov 2010 06:46:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2010/11/15/133653.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/133653.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2010/11/15/133653.html#Feedback</comments><slash:comments>16</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/133653.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/133653.html</trackback:ping><description><![CDATA[



<p align="CENTER" style="margin-bottom: 0cm"><font color="#000000"><font face="Times New Roman, serif"><font size="4" style="font-size: 16pt"><strong>C++</strong></font></font><font size="4" style="font-size: 16pt"><strong>通用删除器设计</strong></font></font></p>
<p align="CENTER" style="margin-bottom: 0cm">版本：<font face="Times New Roman, serif">0.1</font></p>
<p align="CENTER" style="margin-bottom: 0cm">最后修改：<font face="Times New Roman, serif">2010-11-15</font></p>
<p align="CENTER" style="margin-bottom: 0cm">撰写：李现民</p>
<p lang="zh-CN" align="CENTER" style="margin-bottom: 0cm"><br>
</p>
<h1 class="cjk">概述</h1>
<p lang="zh-CN" align="LEFT" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>很久以前，我写过一篇短文讨论如何在<font face="Times New Roman, serif">C++</font>项目中避免使用<font face="Times New Roman, serif">delete</font>的设想，基本方法是使用域（<font face="Times New Roman, serif">scope</font>）对象或<font face="Times New Roman, serif">std::auto_ptr</font>代替。尽管当时已经讨论在所有可能的情况，但后面在实际项目实施中发现效果并不好。原因是方面的，比如在使用<font face="Times New Roman, serif">std::auto_ptr</font>时会存在以下不得因素：</p>
<ol>
	<li><p lang="zh-CN" align="LEFT" style="margin-bottom: 0cm">可能的额外开销外（其实很小）；</p>
	</li><li><p lang="zh-CN" align="LEFT" style="margin-bottom: 0cm">你需要时刻小心对象所有权的问题。尽管可能只需要稍微注意一下就可以了，但似乎没有任何程序员喜欢过提心吊胆的日子；</p>
	</li><li><p lang="zh-CN" align="LEFT" style="margin-bottom: 0cm">你不能在容器（比如<font face="Times New Roman, serif">std::vector</font>）中存储<font face="Times New Roman, serif">std::auto_ptr</font>对象；</p>
</li></ol>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">基于以上原因，类似于</span><font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pText
</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">=
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">new</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;</span></font></font></font><span lang="zh-CN">这种直接在堆上申请内存的方式还是在代码得到了大量应用。而接下来就是如何安全、有效的回收这些内存的问题，这也正是本文所讨论的话题。</span></p>
<h2 class="cjk">回收单个堆对象</h2>
<p lang="zh-CN" style="margin-bottom: 0cm; background: #e6e6e6"><font color="#008000"><font face="Times New Roman, serif"><font size="2" style="font-size: 9pt"><span lang="zxx">//
delete a object pointer and reset it<br></span></font></font></font><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">template</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">&lt;</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">class</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">T</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">&gt;
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">T</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*&amp;
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">p</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">{<br></span><span  style="color: rgb(0, 128, 0); font-family: 'Times New Roman', serif; font-size: 12px; ">//
check if T is incomplete type, if it is, the compiler will report an
error<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">typedef</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">char</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">type_must_be_complete</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">[
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">sizeof</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">T</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)?
1: -1 ];<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; "><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">sizeof</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">type_must_be_complete</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span  style="color: rgb(0, 128, 0); font-family: 'Times New Roman', serif; font-size: 12px; ">//
delete the pointer and reset it<br></span><span  style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">delete</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">p</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">p</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
=</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">NULL</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></span><span  style="font-family: 'Times New Roman', serif; font-size: 12px; ">}</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>这是一个模板函数，它主要有三个作用：</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>第一个作用是检查被删除对象的类型完整性。这通常无法引起人们的重视，但在某些情况下可能会导致未定义行为，比如以下代码：</p>
<p style="margin-bottom: 0cm; background: #e6e6e6"><font face="Times New Roman, serif"><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">	</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pText</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">	=
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">new</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></font><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pData</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">	=
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pText</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">delete</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pData</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;</span></font></font></span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	<font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*</span></font></font></font>类对象<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pText
</span></font></font></font>被转换成了拥有<font face="Times New Roman, serif"><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*</span></font></font></font>对象<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pData</span></font></font></font>，并对<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pData
</span></font></font></font>调用了<font face="Times New Roman, serif"><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">delete
</span></font></font></font>删除操作。在这种情况下编译器的行为是未知的，但至少有一点：由于编译器无法推导<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">pData
</span></font></font></font>的原始类型，因此无法调用对象的析构函数。</p>
<p lang="zh-CN" style="margin-bottom: 0cm; background: #e6e6e6"><font face="Times New Roman, serif">	<font color="#008000"><font size="2" style="font-size: 9pt"><span lang="zxx">//
check if T is incomplete type, if it is, the compiler will report an
error<br></span></font></font></font><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">typedef</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">char</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">type_must_be_complete</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">[
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">sizeof</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">T</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)?
1: -1 ];<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; "><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">sizeof</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">type_must_be_complete</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);</span></font></font></span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>这两句代码可以检查被删除对象的类型完整性。其效果发生在编译期，如果对类型不完整的对象调用<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null
</span></font></font></font>删除操作，将引起编译错误。它<font color="#800000">没有运行期开销</font>，因此使用<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null
</span></font></font></font>带来的安全性实际上免费的。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>更加详细的解释可以参考<font face="Times New Roman, serif">boost</font>库中的<font face="Times New Roman, serif">checked_delete.hpp</font>。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	<font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null
</span></font></font></font>的第二个作用是回收堆对象，这没有什么可说的。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	<font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null
</span></font></font></font>的第三个作用是将对象指针设置为<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">NULL</span></font></font></font><font color="#010001"><font size="2" style="font-size: 9pt">，</font></font>这主要是为了应对<font color="#800000">指针有效性检查</font>，属于常规手段。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>另外，注意到<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null
</span></font></font></font>被设计为一个模板函数，在发布版本（<font face="Times New Roman, serif">Release</font>）中，它将以内联代码（<font face="Times New Roman, serif">inline</font>）的形式存在，因此<font color="#800000">不会有运用期函数调用开销</font>。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<h2 class="cjk">回收容器中的堆对象</h2>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm; background: #e6e6e6"><font color="#008000"><font face="Times New Roman, serif"><font size="2" style="font-size: 9pt"><span lang="zxx">//
delete container (std::vector, std::list) items and reset them to
NULL<br></span></font></font></font><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">template</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">&lt;
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">typename</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">InputIterator</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
&gt; </span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">InputIterator</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">first</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">,
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">InputIterator</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">last</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">{<br></span><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">while</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">last</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
!= </span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">first</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">{<br></span><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(*</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">first</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; "><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">++</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">first</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">}<br></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">}<br><span style="color: rgb(0, 128, 0); "><font color="#000000"><br></font>//
delete functor, used for iterative delete<br></span></span><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">struct</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">deleter<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">{<br></span><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">template</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">&lt;
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">typename</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">T</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
&gt; </span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">void</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">operator</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">()(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">T</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*&amp;
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">p</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">{<br></span><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">p</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">}<br></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">};</span></p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>这段代码分为两部分：一个同样叫<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null
</span></font></font></font>的模板函数与一个名为<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">deleter</span></font></font></font>的仿函数。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>先来看第一部分，它同样叫<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null</span></font></font></font>，与前面介绍的那个版本所不同的是它接受一对迭代器作用输入条件，其作用是回收<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">[first,
last)
</span></font></font></font>范围内所有堆对象。与<font face="Times New Roman, serif">std::for_each</font>等很多<font face="Times New Roman, serif">STL</font>标准算法类似，该函数可以同时应用于<font color="#800000">普通数组或存储单值的标准容器</font>（包括<font face="Times New Roman, serif">std::vector,
std::list, std::set</font>等，不包含<font face="Times New Roman, serif">std::map</font>）。</p>
<p lang="zh-CN" style="margin-bottom: 0cm"><br>
</p>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font>第二部分比较有意思：它是一个仿函数。它可以在一定程度上代替<font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null(first,
last)</span></font></font></font>，<span lang="zh-CN">以下代码展示了分别使用这两种方式回收容器中的堆对象的方法</span>：</p>
<p style="margin-bottom: 0cm; background: #e6e6e6"><font face="Times New Roman, serif"><font size="2" style="font-size: 9pt"><span lang="zxx">	</span></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">typedef</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">std</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">::</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">vector</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">&lt;</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">*&gt;
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">TextPack</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></font><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">TextPack</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts1</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">,
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts2</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">const</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">int</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">datasize</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">	=
100;<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; "><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">for</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
(</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">int</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">i</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">=
0; </span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">i</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">&lt;
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">datasize</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">;
++</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">i</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">)<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">{<br></span><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts1</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">.</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">push_back</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">new</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts2</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">.</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">push_back</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#0000ff"><font size="2" style="font-size: 9pt"><span lang="zxx">new</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">Text</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">);<br></span></font></font></span><span style="font-family: 'Times New Roman', serif; font-size: 12px; ">}<br><span style="font-family: Simsun; font-size: medium; "><font face="Times New Roman, serif"><font color="#008000"><font size="2" style="font-size: 9pt"><span lang="zxx"><font color="#000000"><br></font>//
</span></font></font></font></span><span style="font-family: Simsun; font-size: medium; "><font color="#008000"><font size="2" style="font-size: 9pt">使用</font><font face="Times New Roman, serif"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null<br></span></font></font></font></span></span><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">delete_null</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts1</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">.</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">begin</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(),
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts1</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">.</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">end</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">());<br></span></font></font></span><font face="Times New Roman, serif"><font color="#008000"><font size="2" style="font-size: 9pt"><span lang="zxx">//
</span></font></font></font><font color="#008000"><font size="2" style="font-size: 9pt">使用</font><font face="Times New Roman, serif"><font size="2" style="font-size: 9pt"><span lang="zxx">deleter<br></span></font></font></font><span style="font-family: 'Times New Roman', serif; "><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">std</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">::</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">for_each</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts2</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">.</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">begin</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(),
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">uTexts2</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">.</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">end</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">(),
</span></font></font><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">deleter</span></font></font><font color="#000000"><font size="2" style="font-size: 9pt"><span lang="zxx">());</span></font></font></span></p>
<p style="margin-bottom: 0cm"><br>
</p>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">可以看到前者稍微简洁一些（包括最终的汇编代码），那么问题来了：为什么还需要代码量更大一些的</span><font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">deleter
</span></font></font></font><span lang="zh-CN">仿函数？</span></p>
<p style="margin-bottom: 0cm"><font face="Times New Roman, serif">	</font><span lang="zh-CN">理由是：</span><font color="#800000"><span lang="zh-CN">并不是所有存储堆对象的集合都是直接存储对象指针的</span></font><span lang="zh-CN">。比如可以将指针存储在</span><font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">std::map</span></font></font></font><span lang="zh-CN">中&#8220;值&#8221;部分，甚至有些自定义集合只提供了遍历函数（类似于</span><font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">std::for_each</span></font></font></font><span lang="zh-CN">），但并不公开迭代器接口。在这些情况下，我们就可以使用</span><font face="Times New Roman, serif"><font color="#010001"><font size="2" style="font-size: 9pt"><span lang="zxx">deleter
</span></font></font></font><span lang="zh-CN">仿函数进行堆对象回收。</span></p>
<p style="margin-bottom: 0cm"><br>
</p>
<p style="margin-bottom: 0cm"><br></p><img src ="http://www.cppblog.com/xmli/aggbug/133653.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2010-11-15 14:46 <a href="http://www.cppblog.com/xmli/archive/2010/11/15/133653.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>VC6中的简易delegate实现</title><link>http://www.cppblog.com/xmli/archive/2009/09/01/94977.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Tue, 01 Sep 2009 06:47:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2009/09/01/94977.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/94977.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2009/09/01/94977.html#Feedback</comments><slash:comments>17</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/94977.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/94977.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: VC6中的简易delegate实现版本：0.1最后修改：2009-09-01撰写：李现民	其实原本不想自己写C++委托类的，因为CodeProject已经有许多相关讨论了，国内的前辈也写了很多，但经过一一试用后我无奈的发现它们无一例外的都使用了大量的template技巧，而一些像偏特化之类的template特性在VC6中并没有得到支持。于是只好自己动手了，虽然粗陋，但好在还...&nbsp;&nbsp;<a href='http://www.cppblog.com/xmli/archive/2009/09/01/94977.html'>阅读全文</a><img src ="http://www.cppblog.com/xmli/aggbug/94977.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2009-09-01 14:47 <a href="http://www.cppblog.com/xmli/archive/2009/09/01/94977.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>get与set成员函数是为代码耦合之重要原因</title><link>http://www.cppblog.com/xmli/archive/2009/08/21/94006.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Fri, 21 Aug 2009 03:20:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2009/08/21/94006.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/94006.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2009/08/21/94006.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/94006.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/94006.html</trackback:ping><description><![CDATA[<meta http-equiv="CONTENT-TYPE" content="text/html; charset="utf-8"">
<title></title>
<meta name="GENERATOR" content="OpenOffice.org 3.1  (Win32)"><style type="text/css">
<!--
@page { margin: 2cm }
P { margin-bottom: 0.21cm }
-->
</style>
<p style="margin-bottom: 0cm;" align="CENTER"><font color="#000000"><font face="Times New Roman, serif"><font style="font-size: 16pt;" size="4"><strong>get</strong></font></font><font style="font-size: 16pt;" size="4"><strong>与</strong></font><font face="Times New Roman, serif"><font style="font-size: 16pt;" size="4"><strong>set</strong></font></font><font style="font-size: 16pt;" size="4"><strong>成员函数是为代码耦合之重要原因</strong></font></font></p>
<p style="margin-bottom: 0cm;" align="CENTER">版本：<font face="Times New Roman, serif">0.1</font></p>
<p style="margin-bottom: 0cm;" align="CENTER">最后修改：<font face="Times New Roman, serif">2009-08-21</font></p>
<p style="margin-bottom: 0cm;" align="CENTER">撰写：李现民</p>
<p style="margin-bottom: 0cm;" align="CENTER" lang="zh-CN"><br>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>类数据成员的访问级别通常需定义为<font face="Times New Roman, serif">private</font>，以封装类的实现细节，这样可以在类的生命演化过程中提供更好实现弹性。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	get/set</font>成员函数（访问级别通常为<font face="Times New Roman, serif">public</font>）使得<font face="Times New Roman, serif">client</font>端用户代码可以访问对象的内部数据结构，这会暴露类内部的实现细节。这种暴露使会得用户代码与类实现之间产生深层次的依赖关系，而这种过剩的知识将在类实现技术改变时迅速破坏相关的用户代码<font face="Times New Roman, serif">---</font>涟漪效果。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>比如<font face="Times New Roman, serif">Container</font>类输出了关于实现该类之二叉树的信息（比如，当它输出成员函数<font face="Times New Roman, serif">getLeftChild()</font>与<font face="Times New Roman, serif">getRightChild()</font>时），用户将被迫按照二叉树而不是容器进行思考，这将使用户代码变得复杂且难以改变。如果<font face="Times New Roman, serif">Container</font>类改变了实现结构，则用户代码将被迫进行修改（可能是大量的）。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>最少知识（<font face="Times New Roman, serif">least
knowledge</font>）原则是用于面向对象编码中降低类间耦合度的指导原则。该原则认为如果要在相互调用的类（对象）之间保持较低的耦合度，则一个对象所调用的方法应该仅仅局限于以下几个来源：</p>
<ol>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">类对象本身；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">被当作方法的参数而传递进来的对象；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">此方法所创建或实例化的任何对象；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">对象的任何组件；</p>
    </li>
</ol>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>一个对象可以任意调用以上四类对象的方法。唯一一类不可调用的方法来源于：通过某个对象的<font face="Times New Roman, serif">get</font>成员函数所获取的间接对象的成员函数。很容易想象，当某个类拥有大量<font face="Times New Roman, serif">get/set</font>成员函数时，该类本身几乎不可能提供完善的逻辑处理方法（否则也就没有必要提供这些<font face="Times New Roman, serif">get/set</font>成员函数了），因此借助<font face="Times New Roman, serif">get</font>成员函数获取间接对象并做进一步的处理几乎是不可避免的。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>因此，在有可能的情况下，类设计人员应该尽量不提供<font face="Times New Roman, serif">get</font>与<font face="Times New Roman, serif">set</font>成员函数。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>当然，不要认为<font face="Times New Roman, serif">get</font>与<font face="Times New Roman, serif">set</font>成员函数总是坏的，像<font face="Times New Roman, serif">CORBA</font>这样的框架都会为所有的属性自动提供<font face="Times New Roman, serif">get/set</font>成员函数。真正的问题是：好的对象总会封装并在接口后面隐藏某些东西，然而<font face="Times New Roman, serif">get/set</font>成员函数有时会在暗中暴露对象的秘密。只有当在类外（从用户的角度）看待这些私有数据仍&#8220;有意义&#8221;时，为私有数据设置公有的<font face="Times New Roman, serif">get()</font>和<font face="Times New Roman, serif">set()</font>成员函数才是合理的。然而在许多情况下，
<font face="Times New Roman, serif">get()/set()</font>成员函数和公有数据一样差劲：它们仅仅隐藏了私有数据的名称，而没有隐藏私有数据本身。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN">注<font face="Times New Roman, serif">1</font>：以上文字部分参考了《<font face="Times New Roman, serif">C++
FAQs</font>》<font face="Times New Roman, serif">second edition,
P73</font>的内容。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN">注<font face="Times New Roman, serif">2</font>：我们经常使用<font face="Times New Roman, serif">get/set</font>成员函数作为急救带来修补蹩脚的接口。</p><img src ="http://www.cppblog.com/xmli/aggbug/94006.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2009-08-21 11:20 <a href="http://www.cppblog.com/xmli/archive/2009/08/21/94006.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>基类角色之对象管理器</title><link>http://www.cppblog.com/xmli/archive/2009/07/02/89064.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Thu, 02 Jul 2009 04:49:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2009/07/02/89064.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/89064.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2009/07/02/89064.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/89064.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/89064.html</trackback:ping><description><![CDATA[<meta http-equiv="CONTENT-TYPE" content="text/html; charset=" utf-8="">
<title></title>
<meta name="GENERATOR" content="OpenOffice.org 3.0  (Win32)"><style type="text/css">
<!--
@page { margin: 2cm }
H3 { margin-top: 0cm; margin-bottom: 0cm; page-break-inside: avoid }
H3.western { font-family: "Times New Roman", serif; font-size: 12pt }
H3.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt; font-style: normal }
H3.ctl { font-family: "Tahoma"; font-size: 16pt }
P { margin-bottom: 0.21cm }
-->
</style>
<p style="margin-bottom: 0cm;" align="CENTER" lang="zh-CN"><font color="#000000"><font style="font-size: 16pt;" size="4"><strong>基类角色之对象管理器</strong></font></font></p>
<p style="margin-bottom: 0cm;" align="CENTER">版本：<font face="Times New Roman, serif">0.1</font></p>
<p style="margin-bottom: 0cm;" align="CENTER">最后修改：<font face="Times New Roman, serif">2009-07-02</font></p>
<p style="margin-bottom: 0cm;" align="CENTER">撰写：李现民</p>
<p style="margin-bottom: 0cm;" align="CENTER"><br>
</p>
<h3 class="cjk">问题描述</h3>
<p style="margin-bottom: 0cm;"><font face="Times New Roman, serif">	C++</font><span lang="zh-CN">程序设计中，保存一个生命周期不是由类对象自己维护的其它对象的指针通常是个坏主意，因为程序逻辑很难判断在使用该指针的时刻其所指对象是否已经被销毁。这种应用需求很常见，例如在网游设计中，由于华丽的装备加载需要进行大量硬盘</span><font face="Times New Roman, serif">I/O</font><span lang="zh-CN">，因此加载过程通常由一个独立的加载线程执行，由于在装备加载完成的时刻该玩家很可能已经下线，因此加载线程就需要能够去判断此时玩家对象是否仍然有效。</span></p>
<p style="margin-bottom: 0cm;"><font face="Times New Roman, serif">	</font><span lang="zh-CN">为了解决该问题，通常会设计一个</span><font face="Times New Roman, serif">PlayerManager</font><span lang="zh-CN">类用于跟踪管理当前所有的玩家对象，而加载线程通过提供玩家</span><font face="Times New Roman, serif">id</font><span lang="zh-CN">以确认该玩家对象仍然存在。此种设计方案需要一个独立的</span><font face="Times New Roman, serif">PlayerManager</font><span lang="zh-CN">类，并提供一个全局的</span><font face="Times New Roman, serif">PlayerManager</font><span lang="zh-CN">类对象以跟踪当前的所有玩家对象。</span></p>
<p style="margin-bottom: 0cm;"><font face="Times New Roman, serif">	</font><span lang="zh-CN">出于代码复用的目的，我希望实现一个通用基类解决此类问题。该基类需要为子类对象至少提供以下几方面的能力：</span></p>
<ol>
    <li>
    <p style="margin-bottom: 0cm;"><span lang="zh-CN">为所有的对象分配一个全局唯一的</span><font face="Times New Roman, serif">index</font><span lang="zh-CN">，通过该</span><font face="Times New Roman, serif">index</font><span lang="zh-CN">能够（尽可能快的）获取到拥有该</span><font face="Times New Roman, serif"><span style="font-style: normal;">index</span></font><span lang="zh-CN"><span style="font-style: normal;">的类</span></span><span lang="zh-CN">对象（或</span><font face="Times New Roman, serif">NULL</font><span lang="zh-CN">）；</span></p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">自动跟踪类对象的生成与销毁，不需要手工编写额外代码；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">实现迭代器，提供遍历当前所有有效对象的能力；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">提供&#8220;移除&#8221;接口，使得对象可以主动要求放弃被对象管理器跟踪；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">各子类实现拥有完全独立的管理器逻辑；</p>
    </li>
</ol>
<p style="margin-bottom: 0cm;"><br>
</p>
<h3 class="cjk">解决方案</h3>
<p style="margin-bottom: 0cm;"><font face="Times New Roman, serif">	</font><span lang="zh-CN">将实现代码保存为</span><font face="Times New Roman, serif">objectman.hpp</font>，内容<span lang="zh-CN">如下：</span></p>
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #008000;">/*</span><span style="color: #008000;">*******************************************************************<br>created:&nbsp;&nbsp;&nbsp;&nbsp;2009-06-29<br>author:&nbsp;&nbsp;&nbsp;&nbsp;lixianmin<br><br>purpose:&nbsp;&nbsp;&nbsp;&nbsp;base&nbsp;class&nbsp;for&nbsp;object&nbsp;manager<br>Copyright&nbsp;(C)&nbsp;2009&nbsp;-&nbsp;All&nbsp;Rights&nbsp;Reserved<br>********************************************************************</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>#ifndef&nbsp;_LIB_OBJECT_MAN_HPP_INCLUDED_<br></span><span style="color: #0000ff;">#define</span><span style="color: #000000;">&nbsp;_LIB_OBJECT_MAN_HPP_INCLUDED_</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">cassert</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">map</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br><br></span><span style="color: #0000ff;">namespace</span><span style="color: #000000;">&nbsp;lib<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;objectman<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;index_t;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;索引类型</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typedef&nbsp;std::map</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">index_t,&nbsp;T</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;object_map;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;容器类型</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">enum</span><span style="color: #000000;">&nbsp;{&nbsp;INVAID_INDEX</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">};&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;无效索引</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;迭代器</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;iterator<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;iterator(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">):&nbsp;_iter(_mObjects.begin()){}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;构造函数</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">bool</span><span style="color: #000000;">&nbsp;has_next(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;{&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;(_mObjects.end()</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;_iter);&nbsp;}&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;测试是否还有下一个对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;next(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)&nbsp;{&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;has_next()</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;(_iter</span><span style="color: #000000;">++-&gt;</span><span style="color: #000000;">second):&nbsp;NULL;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;&nbsp;&nbsp; </span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;获取下一个对象指针</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;object_map::iterator&nbsp;_iter;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;构造函数</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objectman(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enable_index();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;copy&nbsp;构造函数</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objectman(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;objectman</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;rhs)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;enable_index();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;析构函数</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">virtual</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">~</span><span style="color: #000000;">objectman(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;disable_index();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;赋值操作符</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;objectman</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">operator</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;objectman</span><span style="color: #000000;">&amp;</span><span style="color: #000000;">&nbsp;rhs)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;通过索引获取对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;get_by_index(index_t&nbsp;index)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;object_map::iterator&nbsp;iter</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;_mObjects.find(index);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(_mObjects.end()</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;iter)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;T</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pObject</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;iter</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">second;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(NULL</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;pObject);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;pObject;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;获取对象索引</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index_t&nbsp;get_index(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;{&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;_idxObject;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;生成索引（使能被对象管理器遍历到）</span><span style="color: #008000;"><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;enable_index(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_idxObject</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">_idxGenderator;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(get_index()</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;INVAID_INDEX);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(_mObjects.find(get_index())</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;_mObjects.end());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mObjects.insert(std::make_pair(get_index(),&nbsp;static_cast</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">*&gt;</span><span style="color: #000000;">(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">)));<br>&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: #008000;">//</span><span style="color: #008000;">&nbsp;移除索引（使不能被对象管理器遍历到）</span><span style="color: #008000;"><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;disable_index(</span><span style="color: #0000ff;">void</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(get_index()</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;INVAID_INDEX)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(_mObjects.find(get_index())</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;_mObjects.end());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_mObjects.erase(get_index());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_idxObject</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;INVAID_INDEX;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">:<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;friend&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;iterator;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;object_map&nbsp;&nbsp;&nbsp;&nbsp;_mObjects;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp; &nbsp; </span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;对象容器</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;index_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_idxGenderator;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;索引发生器</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index_t&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_idxObject;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;&nbsp; </span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;对象索引</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;};<br><br>&nbsp;&nbsp;&nbsp;&nbsp;template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;objectman</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::object_map&nbsp;objectman</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::_mObjects;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;template</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">typename&nbsp;T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;typename&nbsp;objectman</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::index_t&nbsp;objectman</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">T</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">::_idxGenderator</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;<br>}<br><br></span><span style="color: #0000ff;">#endif</span><span style="color: #000000;"><br></span></div>
<br>
<p style="margin-bottom: 0cm;" lang="zh-CN">
<meta http-equiv="CONTENT-TYPE" content="text/html; charset="utf-8"">
<title></title>
<meta name="GENERATOR" content="OpenOffice.org 3.0  (Win32)"><style type="text/css">
<!--
@page { margin: 2cm }
H3 { margin-top: 0cm; margin-bottom: 0cm; page-break-inside: avoid }
H3.western { font-family: "Times New Roman", serif; font-size: 12pt }
H3.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt; font-style: normal }
H3.ctl { font-family: "Tahoma"; font-size: 16pt }
P { margin-bottom: 0.21cm }
-->
</style>
<h3 class="cjk">测试代码</h3>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	</font>测试代码如下：</p>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN">
<div style="border: 1px solid #cccccc; padding: 4px 5px 4px 4px; background-color: #eeeeee; font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: #000000;">#include&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">cassert</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>#include&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">objectman.hpp</span><span style="color: #000000;">"</span><span style="color: #000000;"><br></span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;声明一个类</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Player:</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;lib::objectman</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">Player</span><span style="color: #000000;">&gt;</span><span style="color: #000000;"><br>{<br><br>};<br><br></span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;main(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;argc,&nbsp;</span><span style="color: #0000ff;">char</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;argv[])<br>{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;idxDisabled</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">5</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;生成对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;i</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">10</span><span style="color: #000000;">;&nbsp;</span><span style="color: #000000;">++</span><span style="color: #000000;">i)<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Player</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pPlayer</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Player;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(idxDisabled</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;pPlayer</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">get_index())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;从对象管理器中移除该对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPlayer</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">disable_index();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&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;Player::iterator&nbsp;iter;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">(iter.has_next())<br>&nbsp;&nbsp;&nbsp;&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Player</span><span style="color: #000000;">*</span><span style="color: #000000;">&nbsp;pPlayer</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;iter.next();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">const</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;idxPlayer</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;pPlayer</span><span style="color: #000000;">-&gt;</span><span style="color: #000000;">get_index();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;断言之：遍历不到已经移除的对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(idxPlayer</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;idxDisabled);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;断言之：可以通过idxPerson取得对象指针</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assert(pPlayer</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;Player::get_by_index(idxPlayer));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;回收对象</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;delete&nbsp;pPlayer;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;pPlayer</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;NULL;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">&nbsp;断言之：所有对象均已被删除</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;Player::iterator&nbsp;iter2;<br>&nbsp;&nbsp;&nbsp;&nbsp;assert(</span><span style="color: #000000;">!</span><span style="color: #000000;">iter2.has_next());<br><br>&nbsp;&nbsp;&nbsp;&nbsp;system(</span><span style="color: #000000;">"</span><span style="color: #000000;">pause</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;<br>}</span></div>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN">
<meta http-equiv="CONTENT-TYPE" content="text/html; charset="utf-8"">
<title></title>
<meta name="GENERATOR" content="OpenOffice.org 3.0  (Win32)"><style type="text/css">
<!--
@page { margin: 2cm }
H3 { margin-top: 0cm; margin-bottom: 0cm; page-break-inside: avoid }
H3.western { font-family: "Times New Roman", serif; font-size: 12pt }
H3.cjk { font-family: "Lucida Sans Unicode"; font-size: 12pt; font-style: normal }
H3.ctl { font-family: "Tahoma"; font-size: 16pt }
P { margin-bottom: 0.21cm }
-->
</style>
<p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">	vs2008</font>下所有断言均动作通过。</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p>
<h3 class="cjk">已知问题</h3>
<ol>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN">在大量生成对象的情况下，<font face="Times New Roman, serif">index</font>索引空间（代码定义为<font face="Times New Roman, serif">int</font>的范围）有可能使用殆尽，甚至产生重复，这会导致两个对象拥有相同<font face="Times New Roman, serif">index</font>的严重错误；</p>
    </li>
    <li>
    <p style="margin-bottom: 0cm;" lang="zh-CN"><font face="Times New Roman, serif">std::map</font>的查找速度不是特别另人满意；</p>
    </li>
</ol>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br></p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p>
<p style="margin-bottom: 0cm;" lang="zh-CN"><br>
</p><img src ="http://www.cppblog.com/xmli/aggbug/89064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2009-07-02 12:49 <a href="http://www.cppblog.com/xmli/archive/2009/07/02/89064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>抽象类角色之Simple Factory</title><link>http://www.cppblog.com/xmli/archive/2009/05/15/83064.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Fri, 15 May 2009 09:52:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2009/05/15/83064.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/83064.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2009/05/15/83064.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/83064.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/83064.html</trackback:ping><description><![CDATA[&nbsp;
<p style="MARGIN-BOTTOM: 0cm" align=center><font color=#000000><font face="Times New Roman, serif"><font style="FONT-SIZE: 16pt" size=4><strong></strong></font></font></font>&nbsp;</p>
<p style="MARGIN-BOTTOM: 0cm" align=center>版本：<font face="Times New Roman, serif">0.1</font></p>
<p style="MARGIN-BOTTOM: 0cm" align=center>最后修改：<font face="Times New Roman, serif">2009-05-15</font>&nbsp;</p>
<p style="MARGIN-BOTTOM: 0cm" align=center>撰写：李现民<br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>依赖倒置原则（<font face="Times New Roman, serif">DIP</font>）告诉我们应该优先依赖于抽象类，而避免依赖于具体类。特别是在一个正在进行开发的应用程序，有很多具体都是非常易变的，因此我们应该依赖于抽象接口，以使我们钟爱大多数变化的影响。</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>在典型的面向抽象的程序设计逻辑中，依赖于抽象往往意味着会衍生大量的抽象类及（更大量的）子类，从而构成一些树状的类族结构。一个必然会出现的问题是：<font color=#800000>抽象类族中子类对象由谁创建</font>？</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>显然，这不应该交由客户代码处理（我们不是要依赖于抽象嘛<font face="Times New Roman, serif">:)</font>）。一个典型的基于<font face="Times New Roman, serif">Factory Method</font>解决方案结构如下：<br><img height=272 alt="" src="http://www.cppblog.com/images/cppblog_com/xmli/factory_method.png" width=544 align=middle border=0></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm" align=left><font face="Times New Roman, serif"></font>该类图展现了这样的一个应用场景：类<font face="Times New Roman, serif">SomeApp</font>通过接口<font face="Times New Roman, serif">Shape</font>与<font face="Times New Roman, serif">ShapeFactory</font>对产品类（<font face="Times New Roman, serif">Shape</font>类族）进行操作。<font face="Times New Roman, serif">SomeApp</font>完全没有使用<font face="Times New Roman, serif">Square</font>类或者<font face="Times New Roman, serif">Circle</font>类的任何特定方法。并且由于<font face="Times New Roman, serif">ShapeFactory</font>的介入，<font face="Times New Roman, serif">SomeApp</font>对这两个实现类的创建过程也一无所知。我知道您的疑问：&#8220;对具体类<font face="Times New Roman, serif">ShpeFactoryImplementation</font>的依赖如果处理？&#8221;。答案是：工厂类对象往往由<font face="Times New Roman, serif">main</font>或者由一个隶属于<font face="Times New Roman, serif">main</font>的初始化函数创建出来。</p>
<p style="MARGIN-BOTTOM: 0cm" align=left><font face="Times New Roman, serif"></font><span lang=zh-CN>使用</span><font face="Times New Roman, serif">Factory Method</font><span lang=zh-CN>是有代价的：</span><font color=#800000><span lang=zh-CN>它很复杂</span></font><span lang=zh-CN>，为了创建一个新类，就必须要创建出</span><font face="Times New Roman, serif">4</font><span lang=zh-CN>个新类，这</span><font face="Times New Roman, serif">4</font><span lang=zh-CN>个类是：</span><font face="Times New Roman, serif">2</font><span lang=zh-CN>个表示该新类及其工厂的接口类，</span><font face="Times New Roman, serif">2</font><span lang=zh-CN>个实现这些接口的具体类。尤其是在一个正在演化的设计的初期，如果缺省使用它们，就会棉套的增加扩展设计的难度。</span></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm" align=left><font face="Times New Roman, serif"></font>另一个很常见的问题是：在整个项目的生命周期中，<font face="Times New Roman, serif">ShapeFactory</font>很可能会自始至终保持仅有<font face="Times New Roman, serif">ShpeFactoryImplementation</font>一个子类。结果是这带来了设计上的复杂性，但却在易于扩展性上得到实际的好处。</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm" align=left><font face="Times New Roman, serif"></font>一个折衷的解决方案是使用<font face="Times New Roman, serif">Simple Factory</font>，其类图结构如下所示：<br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm" align=left><font face="Times New Roman, serif"></font><img height=268 alt="" src="http://www.cppblog.com/images/cppblog_com/xmli/simple_factory.png" width=520 align=middle border=0><br>注意<font face="Times New Roman, serif">Simple Factory</font>虽然为很多设计模式的书所津津乐道，但其实并不是<font face="Times New Roman, serif">GOF</font>的<font face="Times New Roman, serif">23</font>种设计模式之一。同时，聪明的你一定已经发现现在<font face="Times New Roman, serif">ShapeFactory</font>类已经不再是一个接口了。难道我们又陷入到对具体类的依赖中去了？哦，如果是的话，至少此时我们所依赖的具体类只有<font face="Times New Roman, serif">ShapeFactory</font>一个，这并不会随着抽象类<font face="Times New Roman, serif">Shape</font>子类的增多而增多。</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>新的问题是：除非<font face="Times New Roman, serif">ShapeFactory</font>负责所有<font face="Times New Roman, serif">Shape</font>对象的管理与维护（这时通常应该叫<font face="Times New Roman, serif">ShapeMan</font>云云。注意：<font face="Times New Roman, serif">Man for manager</font>，工厂类的命名中不一定要含有<font face="Times New Roman, serif">Factory</font>字样的<font face="Times New Roman, serif">:)</font>），否则它极容易成为一个贫血类<font face="Times New Roman, serif">----</font>仅仅含有一个<font face="Times New Roman, serif">CreateShape()</font>函数的类，它披着<font face="Times New Roman, serif">class</font>的皮，干着<font face="Times New Roman, serif">function</font>的事。</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>既然如此，何必要额外创建一个<font face="Times New Roman, serif">ShapeFactory</font>对象（计算机说：这会降低效率的），把<font face="Times New Roman, serif">CreateShape() </font>交给<font face="Times New Roman, serif">Shape</font>类不就得了？反正是她的孩子，也算天经地义（其实，不完全这样！）。新的类图呈现为下面的样子：</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><img height=268 alt="" src="http://www.cppblog.com/images/cppblog_com/xmli/simple_factory.png" width=520 align=middle border=0><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>来看看我们的战果：</p>
<ol>
    <li>
    <p style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif">Factory</font><span lang=zh-CN>职能由</span><font face="Times New Roman, serif">Shape</font><span lang=zh-CN>类承担。通常</span><font face="Times New Roman, serif">CreateShape()</font><span lang=zh-CN>可由一个</span><font face="Times New Roman, serif">static</font><span lang=zh-CN>函数实现；</span></p>
    <li>
    <p style="MARGIN-BOTTOM: 0cm"><span lang=zh-CN>完全消除了非必需类，这避免了创建额外新类的代价；</span></p>
    <li>
    <p style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif">SomeApp</font><span lang=zh-CN>类仅依赖一个唯一的类</span><font face="Times New Roman, serif">Shape</font><span lang=zh-CN>，并且</span><font face="Times New Roman, serif">Shape</font><span lang=zh-CN>是一个抽象类，这降低了客户代码与实现类之间的耦合度；</span></p>
    </li>
</ol>
<p style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>已知的代价：</p>
<ol>
    <li>
    <p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font color=#800000>依赖关系环</font>。敏感的读者一定已经发现<font face="Times New Roman, serif">Shape</font>与其实现类之间形成了一种环状依赖，其代价是每添加一种新的<font face="Times New Roman, serif">Shape</font>实现就必须修改<font face="Times New Roman, serif">CreateShape()</font>函数的实现（能够做到不更改接口）。唯一值得庆幸的是：在<font face="Times New Roman, serif">Factory Method</font>与<font face="Times New Roman, serif">Simple Factory</font>的方案中，我们同样无法避免这种双向修改；</p>
    <li>
    <p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"><font color=#800000>Shape</font></font><font color=#800000>所有权问题</font>。尽管继承是一种比关联强得多的实体关系，但在打包时<font face="Times New Roman, serif">Shape</font>最好与它的客户代码<font face="Times New Roman, serif">SomeApp</font>在一起。<font face="Times New Roman, serif">SomeApp</font>的实现离不开<font face="Times New Roman, serif">Shape</font>，但理论上<font face="Times New Roman, serif">Shape</font>却是可以脱离<font face="Times New Roman, serif">Shape</font>单独存在。依赖关系环的出现会强迫<font face="Times New Roman, serif">Shape</font>与它的实现类打包在一起；</p>
    <li>
    <p lang=zh-CN style="MARGIN-BOTTOM: 0cm">违反了依赖倒置原则（<font face="Times New Roman, serif">DIP</font>），我们的抽象类开始依赖于具体类；</p>
    <li>
    <p style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif">Shape</font><span lang=zh-CN>不再是一个接口。如果说</span><font face="Times New Roman, serif">Factory Method</font><span lang=zh-CN>与</span><font face="Times New Roman, serif">Simple Factory</font><span lang=zh-CN>中的</span><font face="Times New Roman, serif">Shape</font><span lang=zh-CN>还有可能是接口的话，那么在最后一方案中具体函数</span><font face="Times New Roman, serif">CreateShape()</font><span lang=zh-CN>的加入则完全打破了这种可能。</span></p>
    </li>
</ol>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><font face="Times New Roman, serif"></font>如果：在一个项目演化的初期，您还不确信您需要创建一些<font face="Times New Roman, serif">Factory</font>类；或者，您已经确信可以承受该方案的代价并且期望得到它所带来的好处的话，那么您不妨尝试一下。</p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm">参考文献</p>
<ol>
    <li>
    <p lang=zh-CN style="MARGIN-BOTTOM: 0cm">《敏捷软件开发 原则、模式与实践》 <font face="Times New Roman, serif">P239</font>：<font face="Times New Roman, serif">FACTORY</font>模式；<font face="Times New Roman, serif">P279</font>：<font face="Times New Roman, serif">ABSTRACT SERVER</font>模式；</p>
    </li>
</ol>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<p lang=zh-CN style="MARGIN-BOTTOM: 0cm"><br></p>
<img src ="http://www.cppblog.com/xmli/aggbug/83064.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2009-05-15 17:52 <a href="http://www.cppblog.com/xmli/archive/2009/05/15/83064.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>C++项目的敏捷实践</title><link>http://www.cppblog.com/xmli/archive/2009/04/27/81245.html</link><dc:creator>李现民</dc:creator><author>李现民</author><pubDate>Mon, 27 Apr 2009 09:59:00 GMT</pubDate><guid>http://www.cppblog.com/xmli/archive/2009/04/27/81245.html</guid><wfw:comment>http://www.cppblog.com/xmli/comments/81245.html</wfw:comment><comments>http://www.cppblog.com/xmli/archive/2009/04/27/81245.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/xmli/comments/commentRss/81245.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/xmli/services/trackbacks/81245.html</trackback:ping><description><![CDATA[关于Agile的，感觉挺不错，请到这里去看 <a href="http://www.infoq.com/cn/presentations/yuanyingjie-cplusplus-agile">http://www.infoq.com/cn/presentations/yuanyingjie-cplusplus-agile</a><br> <img src ="http://www.cppblog.com/xmli/aggbug/81245.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/xmli/" target="_blank">李现民</a> 2009-04-27 17:59 <a href="http://www.cppblog.com/xmli/archive/2009/04/27/81245.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>