﻿<?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>BlogJava-庄周梦蝶，孰蝶是我，我是孰蝶？一梦至今，蝶我已难分-随笔分类-设计模式</title><link>http://www.blogjava.net/killme2008/category/19797.html</link><description /><language>zh-cn</language><lastBuildDate>Mon, 07 Apr 2008 16:31:33 GMT</lastBuildDate><pubDate>Mon, 07 Apr 2008 16:31:33 GMT</pubDate><ttl>60</ttl><item><title>模块的设计(书摘）</title><link>http://www.blogjava.net/killme2008/archive/2008/04/06/191022.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sun, 06 Apr 2008 05:00:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/04/06/191022.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/191022.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/04/06/191022.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/191022.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/191022.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 模块化的价值毋庸置疑。<br />
&nbsp;&nbsp;&nbsp; 模块化代码的首要特质就是封装。封装良好的模块不会过多向外部披露自身的细节，不会直接调用其它模块的实现码，也不会胡乱共享全局数据。模块之间通过应用程序编程接口（API）——一组严密、定义良好的程序调用和数据结构来通信。这就是模块化原则的内容。API在模块间扮演双重角色。在实现层面，作为模块之间的滞塞点（choke point），阻止各自的内部细节被相邻模块知晓；在设计层面，正是API(而不是模块间的实现代码)真正定义了整个体系。<br />
&nbsp;&nbsp;&nbsp; 模块的最佳模块大小，逻辑行在200到400之间，物理行在400到800之间为最佳。模块太小，几乎所有的复杂度都集中在接口，同样不利于理解，也就是透明性的欠缺。<br />
&nbsp;&nbsp; 紧凑性就是一个特性能否装进人脑中的特性。理解紧凑性可以从它的&#8220;反面&#8221;来理解，紧凑性不等于&#8220;薄弱&#8221;，如果一个设计构建在易于理解且<strong>利于组合</strong>的抽象概念上，则这个系统能在具有非常强大、灵活的功能的同时保持紧凑。紧凑也不等同于&#8220;容易学习&#8221;：对于某些紧凑
设计而言，在掌握其精妙的内在基础概念模型之前，要理解这个设计相当困难；但一旦理解了这个概念模型，整个视角就会改变，紧凑的奥妙也就十分简单了。紧凑也不意味着&#8220;小巧&#8221;。即使一个设计良好的系统，对有经验的用户来说没什么特异之处、&#8220;一眼&#8221;就能看懂，但仍然可能包含很多部分。<br />
&nbsp;&nbsp;&nbsp; 评测一个API紧凑性的经验法则是：API的入口点通常在7个左右，或者按《代码大全2》的说法，7+2和7-2的范围内。<br />
&nbsp;&nbsp;&nbsp; <span style="font-family: 方正书宋简体;">如果两个或更多事物中的一个发生变化，不会影响其他事物，这些事物就是正交的。每一个动作只改变一件事，不会影响其他（没有其他副作用）。举个例子，比如读取配置文件，获得系统设置信息这个方法：<br />
</span>
<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;">module&nbsp;Config<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;self.load_config<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config_str</span><span style="color: #000000;">=</span><span style="color: #000000;">File.open(</span><span style="color: #800000;">"</span><span style="color: #800000;">r</span><span style="color: #800000;">"</span><span style="color: #000000;">,</span><span style="color: #800000;">"</span><span style="color: #800000;">config.xml</span><span style="color: #800000;">"</span><span style="color: #000000;">).read<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">解析配置文件，可能转化成XML&nbsp;Dom处理等</span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><img src="http://www.blogjava.net/Images/dot.gif"  alt="" /><br />
&nbsp;&nbsp;&nbsp;end<br />
end</span></div>
这个方法想当然地认为配置文件存储于磁盘文件中，然而配置文件完全是有可能通过网络获取的，也就是说文件句柄未必来源于磁盘文件，这个方法承担了两个职责：获取配置数据和解析配置数据。重构一下，以提高正交性：<br />
<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;">module&nbsp;Config<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;self.load_config(io)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config_str</span><span style="color: #000000;">=</span><span style="color: #000000;">io.read<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;parse_config(config_str)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br />
&nbsp;&nbsp;&nbsp;end<br />
&nbsp;&nbsp;&nbsp;private<br />
&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">def</span><span style="color: #000000;">&nbsp;self.parse_config(config_str)<br />
&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">#</span><span style="color: #008000;">解析<img src="http://www.blogjava.net/Images/dot.gif"  alt="" /></span><span style="color: #008000;"><br />
</span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;end&nbsp;<br />
end</span></div>
&nbsp;&nbsp;&nbsp; 重构技术中的很多坏味道，特别是重复代码，是违反正交性的明显例子，&#8220;重构的原则性目标就是提高正交性&#8221;。<br />
&nbsp;&nbsp;&nbsp; DRY（Don't Repeat Yourself)原则，意思是说：任何一个知识点在系统内都应当有一个唯一、明确、权威的表述。这个原则的另一种表述就是所谓SPOT原则（Single Point Of Truth）——真理的单点性。<br />
&nbsp;&nbsp;&nbsp; 提高设计的紧凑性，有一个精妙但强大的方法，就是围绕&#8220;解决一个定义明确的问题&#8221;的强核心算法组织设计，避免臆断和捏造。<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/191022.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-04-06 13:00 <a href="http://www.blogjava.net/killme2008/archive/2008/04/06/191022.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>singleton迷恋</title><link>http://www.blogjava.net/killme2008/archive/2008/02/23/181596.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 23 Feb 2008 07:34:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2008/02/23/181596.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/181596.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2008/02/23/181596.html#Feedback</comments><slash:comments>5</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/181596.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/181596.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 自从知道singleton模式这把锤子是什么样的之后，我就把很多小疙瘩也当成了钉子，时常想象偶顶着模式的光环挥舞着&#8220;万能&#8221;锤子在代码丛林中学习兰博搏斗的光辉形象~~~~。昨天读《重构与模式》的inline singleton一节，一句话点醒梦中人，singleton模式是&#8220;保证一个类仅有一个实例，并提供一个访问它的全局访问点&#8221;，原来——singleton也是全局变量啊。马教主深刻地教育过我们：全局变量在被证明无害之前都是有害。偶大汗淋漓。看看迷恋singleton的几种现象：<br />
1、仅仅在一个地方调用到了某个singleton实例，并且对这个实例的处理代码也集中在这么一两个地方，这样的情况下你为什么要singleton？这里需要一个个全局访问点吗？我看你是为了singleton而singleton。<br />
<br />
2、我为了性能优化啊！singleton只有一个实例，减小了创建开销。oh,我终于找到一个用singleton的充分理由了——性能。慢着，跟我读高大师的名言：&#8220;<span class="5K"><span style="font-family: 楷体_GB2312;">不成熟的优化是万恶之源&#8221;</span></span>。你怎么知道singleton对象的重复创建是明显影响了性能？现代jvm对&#8220;短命&#8221;对象的创建代价已经非常低了。不成熟的优化不仅可能是无效的，而且也给以后重构工作带来了困难。除非有明显数据证明（分析工具而来）某个对象的重复创建是对性能影响极大，否则所谓性能优化不能成为采用singleton模式的理由。<br />
<br />
3、有时候我们需要在系统的不同层次间传递一些共享信息，如果不采用singleton对象来提供这些共享信息，就得在调用的方法中重复地传递这些参数，这是个应用singleton模式的场景。但是，如果这些共享信息是可被修改的，或者说singleton对象不是无状态的，如果还采用singleton模式，那么你就不得不在调用的方法中从single对象取出旧信息和存入新信息，这样的重复代码将遍布的到处都是，不仅仅引入了同步访问的需要，而且出错的风险大大提高。这种情况下你还将这些信息作为方法参数传递而不是采用singleton可能更为清晰和健壮。<br />
<br />
&nbsp;&nbsp;&nbsp; singleton不仅仅是&#8220;保证一个类仅有一个实例&#8221;（这仅仅是描述），更重要的是它是用来&#8220;提供全局访问点&#8221;的（这才是它的功能），不要再迷恋这把锤子，好好利用这把锤子。<br />
<br />
题外话：脚本语言似乎更容易滥用全局变量，javascript里可以模拟命名空间，Ruby也可以模拟类似的机制。最近写的一个比较大一点的Ruby脚本，用了几个全局变量（都是数组）用于保存状态数据，一开始没有意识到这一点，导致对全局变量的访问散落在好几个脚本文件里，RDT下看起来红通通的一片极其不爽。那么就重构吧——封装数组重构，将对这些全局数组的访问和修改操作统一到一个模块，调用全局变量的地方都引用这个模块，通过模块去操作全局变量，代码看起来清爽多了。<br />
<br />
<br /><img src ="http://www.blogjava.net/killme2008/aggbug/181596.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2008-02-23 15:34 <a href="http://www.blogjava.net/killme2008/archive/2008/02/23/181596.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The Future Of the Software Development</title><link>http://www.blogjava.net/killme2008/archive/2007/10/25/155788.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 25 Oct 2007 02:11:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/10/25/155788.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/155788.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/10/25/155788.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/155788.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/155788.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 在未来，我们可能需要的是一个个高效精干的小型团队，团队成员技艺高超，富于激情，易于沟通。&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/10/25/155788.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/155788.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-10-25 10:11 <a href="http://www.blogjava.net/killme2008/archive/2007/10/25/155788.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>谈NullObject模式</title><link>http://www.blogjava.net/killme2008/archive/2007/07/31/133628.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 31 Jul 2007 09:48:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/07/31/133628.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/133628.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/07/31/133628.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/133628.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/133628.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 知道这个模式还是通过《重构》，这个模式的出现还是了为了解决代码重复的坏味道。在项目中很经常见到类似下面这样的代码：<br>
<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: #0000ff;">if</span><span style="color: #000000;">(prj.getProjectId</span><span style="color: #000000;">==</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;plan.setCost(</span><span style="color: #000000;">0.0</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;plan.setCost(prj.getCost());</span></div>
<br>&nbsp;&nbsp; 我们在很多地方有类似的检查对象是否为null，如果为null，需要一个默认值等等这样的场景。显然，代码重复是坏味道，怎么消除这个坏味道呢？答案就是使用NullObject替代之，Null Object继承原对象。<br>
<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;NullProject&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;Project{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;isNull(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;}<br>}<br></span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;Project{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">double</span><span style="color: #000000;">&nbsp;cost;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;String&nbsp;projectId;<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;isNull(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br>那么，原来的代码可以改写为：<br>
<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: #0000ff;">if</span><span style="color: #000000;">(prj.isNull())<br>&nbsp;&nbsp;&nbsp;&nbsp;plan.setCost(</span><span style="color: #000000;">0.0</span><span style="color: #000000;">);<br></span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;plan.setCost(prj.getCost());</span></div>
<br>&nbsp;&nbsp;&nbsp; 如果Null Object的引入仅仅是带来这个好处，似乎没有理由让我们多敲这么多键盘。问题的关键是类似上面这样的判断也许出现在很多处，那么有价值的技巧出现了，我们在NullObject覆写getCost，提供缺省值：<br>
<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;NullProject&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;Project{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;isNull(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">true</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">double</span><span style="color: #000000;">&nbsp;getCost(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0.0</span><span style="color: #000000;">;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;}<br>}</span></div>
&nbsp;&nbsp;&nbsp; 因此，检查对象是否为null的代码可以去掉if...else了：<br>
<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;">plan.setCost(prj.getCost());</span></div>
<br>&nbsp;&nbsp;&nbsp; 请注意，只有那些大多数客户端代码都要求null object做出相同响应时，这样的行为才有意义。比如我们这里当工程id为null，很多地方要求费用就默认为0.0。
特殊的行为我们仍然使用isNull进行判断。<br>&nbsp;&nbsp;&nbsp; 当然，另外在需要返回NullObject的地方，你应该创建一个null object以替代一般的对象，我们可以建立一个工厂方法：<br><br>
<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: #0000ff;">class</span><span style="color: #000000;">&nbsp;Project{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">double</span><span style="color: #000000;">&nbsp;cost;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;String&nbsp;projectId;<br>&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif">.<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">boolean</span><span style="color: #000000;">&nbsp;isNull(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">false</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;Project&nbsp;createNullProject(){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;NullProject();<br>&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br>&nbsp;&nbsp; Null Object模式带来的好处：减少了检查对象是否为null的代码重复，提高了代码的可读性，通常这些Null Object也可以为单元测试带来简便。<br><br><img src ="http://www.blogjava.net/killme2008/aggbug/133628.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-07-31 17:48 <a href="http://www.blogjava.net/killme2008/archive/2007/07/31/133628.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit源码分析(四)——从Decorator模式说起</title><link>http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 06 Apr 2007 04:39:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/108894.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/108894.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/108894.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 其实我这系列小文，名为源码分析，其实是自己读《设计模式》的读书笔记。Decorator模式在java的IO库中得到应用，java的IO库看起来复杂，其实理解了Decorator模式再回头看可以很好理解并使用。<br>&nbsp;&nbsp;&nbsp; Decorator模式，也就是装饰器模式，是对象结构型模式之一。<br><br>1.意图：动态地给一个对象添加一些额外的职责。给对象添加功能，我们首先想到的是继承，但是如果每增一个功能都需要继承，类的继承体系将无可避免地变的庞大和难以理解。面向对象设计的原则：优先使用组合，而非继承，继承的层次深度最好不过三。<br><br>2.适用场景：<br>1）在不影响其他对象的情况下，以动态、透明的方式给单个对象添加额外的责任<br>2）处理可以撤销的职责<br>3）为了避免类的数目爆炸，或者不能采用生成子类的方法进行扩展时<br><br>3.UML图和协作：<br><br><img src="http://www.blogjava.net/images/blogjava_net/killme2008/ShowImg.jpg" border="0"><br><br>Component——定义一个对象接口，可以给这些对象动态地添加职责<br><br>ConcreteComponent——定义一个对象，可以给这个对象添加职责<br><br>Decorator——维持一个指向Component的引用，并定义一个与Component一致的接口，作为装饰类的父类<br><br>ConcreteDecorator——具体装饰类<br><br>4.效果：<br>1）与静态继承相比，Decorator可以动态添加职责，更为灵活<br>2）避免产生复杂的类，通过动态添加职责，而不是一次性提供一个万能的接口<br>3）缺点是将产生比较多的小对象，对学习上有难度，显然，java.io就是这个问题<br><br>我们以一个例子来实现Decorator模式，假设这样一个场景：在某个应用中需要打印票据，我们写了一个PrintTicket接口，然后提供一个实现类（DefaultPrintTicket）实现打印的功能：<br><br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br></span><span style="color: #008000;">//</span><span style="color: #008000;">抽象component接口</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">interface</span><span style="color: #000000;">&nbsp;PrintTicket&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print();<br>}<br><br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">默认实现类，打印票据</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;DefaultPrintTicket&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;PrintTicket&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ticket&nbsp;body</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
<br>OK,我们的功能已经实现，我们还体现了针对接口编程的原则，替换一个新的打印方式很灵活，但是客户开始提需求了——人生无法避免的三件事：交税、死亡和需求变更。客户要求打印页眉，你首先想到的是继承：<br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;AnotherPrintTicket&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;PrintTicket&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ticket&nbsp;header</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ticket&nbsp;body</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
<br>请注意，我们这里只是简单的示例，在实际项目中也许意味着添加一大段代码，并且需要修改打印票据本体的功能。需求接踵而至，客户要求添加打印页码，要求增加打印花纹，要求可以联打......你的类越来越庞大，直到你看见这个类都想吐的地步！-_-。让我们看看另一个方案，使用Decorator模式来动态地给打印增加一些功能，首先是实现一个Decorator，它需要保持一个到PrintTicket接口的引用：<br><br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;PrintTicketDecorator&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;PrintTicket&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;PrintTicket&nbsp;printTicket;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;PrintTicketDecorator(PrintTicket&nbsp;printTicket)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">this</span><span style="color: #000000;">.printTicket&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;printTicket;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">默认调用PrintTicket的print</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;printTicket.print();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
<br>然后，我们实现两个具体的装饰类——打印页眉和页脚：<br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;HeaderPrintTicket&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;PrintTicketDecorator&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;HeaderPrintTicket(PrintTicket&nbsp;printTicket){<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">(printTicket);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ticket&nbsp;header</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">.print();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></span></div>
<br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;FooterPrintTicket&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;PrintTicketDecorator&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;FooterPrintTicket(PrintTicket&nbsp;printTicket)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">(printTicket);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;print()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">.print();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">ticket&nbsp;footer</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}<br></span></div>
<br>&nbsp;&nbsp;&nbsp; 使用起来也很容易：<br>&nbsp;&nbsp;&nbsp;
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;com.rubyeye.design_pattern.decorator;<br><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;DecoratorTest&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@param</span><span style="color: #008000;">&nbsp;args<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String[]&nbsp;args)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PrintTicket&nbsp;print</span><span style="color: #000000;">=</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;HeaderPrintTicket(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;FooterPrintTicket(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;DefaultPrintTicket()));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;print.print();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
<br>输出：<br>ticket header<br>ticket body<br>ticket footer<br><br>&nbsp;&nbsp;&nbsp; 了解了Decorator模式，我们联系了下JUnit里面的应用。作为一个测试框架，应该方便地支持二次开发，也许用户开发自己的TestCase，添加自定义的功能，比如执行重复测试、多线程测试等等。动态添加职责，而又不想使用静态继承，这正是Decorator使用的地方。在junit.extensions包中有一个TestDecorator，正是所有装饰类的父类，也是作为二次开发的基础，它实现了Test接口，而Test接口就是我们定义的抽象接口：<br>
<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: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;TestDecorator&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;&nbsp;Test&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">保有一个指向Test的引用</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;Test&nbsp;fTest;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;TestDecorator(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTest</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;test;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;basicRun(TestResult&nbsp;result) {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; fTest.run(result);<br>&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;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run(TestResult&nbsp;result)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp; &nbsp; &nbsp; &nbsp; basicRun(result);<br>&nbsp;&nbsp; &nbsp; &nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><br>}</span></div>
<br>Junit已经提供了两个装饰类：junit.extensions.ActiveTest用于处理多线程，junit.extensions.RepeatedTest用于执行重复测试，看看RepeatedTest是怎么实现的：<br>
<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: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;RepeatedTest&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;&nbsp;TestDecorator&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&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;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;fTimesRepeat;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;RepeatedTest(Test&nbsp;test,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;repeat)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">(test);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTimesRepeat</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;repeat;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run(TestResult&nbsp;result)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&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;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;fTimesRepeat;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&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;(result.shouldStop())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">.run(result);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"><br>}</span></div>
<br>&nbsp;&nbsp;&nbsp; <span style="color: #000000;">RepeatedTest继承</span><span style="color: #000000;">TestDecorator ，覆写</span><span style="color: #000000;">run（TestReult result）方法，重复执行，super.run(result)将调用传入的TestCase的run(TestResult result)方法，这已经在</span><span style="color: #000000;"></span><span style="color: #000000;">TestDecorator默认实现。看看使用方式，使用装饰模式的好处不言而喻。<br><br>
<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;">TestSuite&nbsp;suite&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TestSuite();<br>suite.addTest(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TestSetup(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;RepeatedTest(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Testmath(</span><span style="color: #000000;">"</span><span style="color: #000000;">testAdd</span><span style="color: #000000;">"</span><span style="color: #000000;">),</span><span style="color: #000000;">12</span><span style="color: #000000;">)));<br><br></span></div>
</span><span style="color: #0000ff;"></span> <img src ="http://www.blogjava.net/killme2008/aggbug/108894.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-06 12:39 <a href="http://www.blogjava.net/killme2008/archive/2007/04/06/108894.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit源码分析 （三）——Template Method模式</title><link>http://www.blogjava.net/killme2008/archive/2007/04/06/108860.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Fri, 06 Apr 2007 01:54:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/06/108860.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/108860.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/06/108860.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/108860.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/108860.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; 在JUnit执行测试时，我们经常需要初始化一些环境供测试代码使用，比如数据库连接、mock对象等等，这些初始化代码应当在每一个测试之前执行并在测试方法运行后清理。在JUnit里面就是相应的setUp和tearDown方法。如果没有这两个方法，那么我们要在每个测试方法的代码内写上一大堆重复的初始化和清理代码，这是多么愚蠢的做法。那么JUnit是怎么让setUp和tearDown在测试执行前后被调用的呢？<br>&nbsp;&nbsp;&nbsp; 如果你查看下TestCase方法，你会发现TestCase和TestSuite的run()方法都是将执行测试的任务委托给了TestResult，由TestResult去执行测试代码并收集测试过程中的信息（这里用到了Collecting Parameter模式）。<br>&nbsp;&nbsp;&nbsp;
<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: #0000ff;">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000;">&nbsp;TestResult&nbsp;run()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TestResult&nbsp;result</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;createResult();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;run(result);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;result;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Runs&nbsp;the&nbsp;test&nbsp;case&nbsp;and&nbsp;collects&nbsp;the&nbsp;results&nbsp;in&nbsp;TestResult.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;This&nbsp;is&nbsp;the&nbsp;template&nbsp;method&nbsp;that&nbsp;defines&nbsp;the&nbsp;control&nbsp;flow<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;for&nbsp;running&nbsp;a&nbsp;test&nbsp;case.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run(TestResult&nbsp;result)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;result.run(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; 我们直接找到TestResult，看看它的run方法：<br>
<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Runs&nbsp;a&nbsp;TestCase.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run(</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;TestCase&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;startTest(test);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Protectable&nbsp;p&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Protectable()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;protect()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Throwable&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.runBare();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;};<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;runProtected(test,&nbsp;p);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;endTest(test);<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br>&nbsp;&nbsp;&nbsp; 这里实例化了一个内部类，内部类实现了<span style="color: #000000;">Protectable接口的 </span><span style="color: #000000;">protect()方法，并执行传入的TestCase的runBare()方法，显然，真正的测试代码在TestCase的runBare()方法中，让我们来看下：<br></span><span style="color: #000000;"><br><br>
<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;">&nbsp;&nbsp;&nbsp;&nbsp;&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;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setUp()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Throwable&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">同上，将被具体的TestCase实现</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;tearDown()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Throwable&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008000;">&nbsp;&nbsp;&nbsp;&nbsp; /**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;模板方法<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Runs&nbsp;the&nbsp;bare&nbsp;test&nbsp;sequence.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;</span><span style="color: #808080;">@exception</span><span style="color: #008000;">&nbsp;Throwable&nbsp;if&nbsp;any&nbsp;exception&nbsp;is&nbsp;thrown<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;runBare()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Throwable&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setUp();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;runTest();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">finally</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;tearDown();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br></span></div>
</span><span style="color: #000000;">真相水落石出，对于每一个测试方法，都遵循这样的模板：setUp-&gt;执行测试 runTest()-&gt;tearDown。这正是模板方式模式的一个应用例子。什么是template method模式呢？<br><br>Template Method模式<br><br>类行为模式的一种<br>1.意图：定义一个操作中的算法的骨架，而将一些延迟步骤到子类中。Template Method使得子类可以不改变一个算法的结构即可重定义该算法的某些步骤。<br>2.适用场景：<br>1）一次性实现算法的不变部分（基本骨架），将可变的行为留给子类来完成<br>2）子类中的公共部分（比如JUnit中的初始化和清理）被抽取到一个公共父类中以避免代码重复。<br>3）控制了子类的扩展，这里其实也有类似回调函数的性质，具体步骤先在骨架中注册，在具体执行时被回调。<br><br>3.UML图和结构<br>&nbsp;&nbsp;&nbsp; <img  src="http://www.blogjava.net/images/blogjava_net/killme2008/template.jpg" border="0"><br>&nbsp; 抽象父类定义了算法的基本骨架（模板方法），而不同的子类实现具体的算法步骤，客户端由此可以与算法的更改隔离。<br><br>4.效果：<br>1）模板方法是代码复用的基本技术，在类库中经常使用，可以减少大量的代码重复<br>2）通过隔离算法的不变和可变部分，增加了系统的灵活性，扩展算法的某些步骤将变的很容易。<br><br>&nbsp;&nbsp;&nbsp; 了解了Template Method模式之后，让我们回到JUnit的源码，看看runTest()方法，这里主要应用的是java的反射技术，对于学习反射技术的有参考价值：<br>
<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: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;runTest()&nbsp;</span><span style="color: #0000ff;">throws</span><span style="color: #000000;">&nbsp;Throwable&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method&nbsp;runMethod</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;runMethod</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;getClass().getDeclaredMethod(fName,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Class[</span><span style="color: #000000;">0</span><span style="color: #000000;">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(NoSuchMethodException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail(</span><span style="color: #000000;">"</span><span style="color: #000000;">Method&nbsp;\</span><span style="color: #000000;">""</span><span style="color: #000000;">+fName+</span><span style="color: #000000;">"</span><span style="color: #000000;">\</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;not&nbsp;found</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(runMethod&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">Modifier.isPublic(runMethod.getModifiers()))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fail(</span><span style="color: #000000;">"</span><span style="color: #000000;">Method&nbsp;\</span><span style="color: #000000;">""</span><span style="color: #000000;">+fName+</span><span style="color: #000000;">"</span><span style="color: #000000;">\</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;should&nbsp;be&nbsp;public</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">try</span><span style="color: #000000;">&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;runMethod.invoke(</span><span style="color: #0000ff;">this</span><span style="color: #000000;">,&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Class[</span><span style="color: #000000;">0</span><span style="color: #000000;">]);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(InvocationTargetException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.fillInStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;e.getTargetException();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">catch</span><span style="color: #000000;">&nbsp;(IllegalAccessException&nbsp;e)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.fillInStackTrace();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">throw</span><span style="color: #000000;">&nbsp;e;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br></span>&nbsp;&nbsp;&nbsp; <br><img src ="http://www.blogjava.net/killme2008/aggbug/108860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-06 09:54 <a href="http://www.blogjava.net/killme2008/archive/2007/04/06/108860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit源码分析（二）——观察者模式</title><link>http://www.blogjava.net/killme2008/archive/2007/04/05/108743.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 05 Apr 2007 09:19:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/05/108743.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/108743.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/05/108743.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/108743.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/108743.html</trackback:ping><description><![CDATA[<br>&nbsp;&nbsp;&nbsp; 我们知道JUnit支持不同的使用方式：swt、swing的UI方式，甚至控制台方式，那么对于这些不同的UI我们如何提供统一的接口供它们获取测试过程的信息（比如出现的异常信息，测试成功，测试失败的代码行数等等）？我们试想一下这个场景，当一个error或者exception产生的时候，测试能够马上通知这些UI客户端：发生错误了，发生了什么错误，错误是什么等等。显而易见，这是一个订阅-发布机制应用的场景，应当使用观察者模式。那么什么是观察者模式呢？<br><br><span style="font-weight: bold;">观察者模式(Observer)<br><br></span>Observer是对象行为型模式之一<br><br>1.意图：定义对象间的一种一对多的依赖关系，当一个对象的状态发现改变时，所有依赖于它的对象都得到通知并被自动更新<br><br>2.适用场景：<br>1）当一个抽象模型有两个方面，其中一个方面依赖于另一个方面，通过观察者模式将这两者封装在不同的独立对象当中，以使它们可以独立的变化和复用<br>2）当一个对象改变时，需要同时改变其他对象，并且不知道其他对象的具体数目<br>3）当一个对象需要引用其他对象，但是你又不想让这个对象与其他对象产生紧耦合的时候<br><br>3.UML图：<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img src="http://www.blogjava.net/images/blogjava_net/killme2008/observer.jpg" border="0"><br>&nbsp;&nbsp; Subject及其子类维护一个观察者列表，当需要通知所有的Observer对象时调用Nitify方法遍历Observer集合，并调用它们的update方法更新。而具体的观察者实现Observer接口（或者抽象类），提供具体的更新行为。其实看这张图，与Bridge有几分相似，当然两者的意图和适用场景不同。<br><br>4.效果：<br>1）目标和观察者的抽象耦合,目标仅仅与抽象层次的简单接口Observer松耦合，而没有与具体的观察者紧耦合<br>2）支持广播通信<br>3）缺点是可能导致意外的更新，因为一个观察者并不知道其他观察者，它的更新行为也许将导致一连串不可预测的更新的行为<br><br>5.对于观察者实现需要注意的几个问题：<br>1）谁来触发更新？最好是由Subject通知观察者更新，而不是客户，因为客户可能忘记调用Notify<br>2)可以通过显式传参来指定感兴趣的更新<br>3）在发出通知前，确保Subject对象状态的一致性，也就是Notify操作应该在最后被调用<br>4）当Subject和Observer的依赖关系比较复杂的时候，可以通过一个更新管理器来管理它们之间的关系，这是与中介者模式的结合应用。<br><br><br>&nbsp;&nbsp;&nbsp; 讨论完观察者模式，那我们来看JUnit是怎么实现这个模式的。在junit.framework包中我们看到了一个Observer接口——TestListener，看看它的代码：<br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;junit.framework;<br><br></span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;*&nbsp;A&nbsp;Listener&nbsp;for&nbsp;test&nbsp;progress<br>&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">interface</span><span style="color: #000000;">&nbsp;TestListener&nbsp;{<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;An&nbsp;error&nbsp;occurred.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addError(Test&nbsp;test,&nbsp;Throwable&nbsp;t);<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;A&nbsp;failure&nbsp;occurred.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addFailure(Test&nbsp;test,&nbsp;Throwable&nbsp;t);&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;A&nbsp;test&nbsp;ended.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;endTest(Test&nbsp;test);&nbsp;<br>&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;A&nbsp;test&nbsp;started.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;startTest(Test&nbsp;test);<br>}</span></div>
<br>&nbsp;&nbsp;&nbsp; 接口清晰易懂，就是一系列将测试过程的信息传递给观察者的操作。具体的子类将接受这些信息，并按照它们的方式显示给用户。<br>&nbsp;&nbsp;&nbsp;&nbsp; 比如，我们看看swing的UI中的TestRunner，它将这些信息显示在一个swing写的UI界面上：<br>
<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;">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;startTest(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;showInfo(</span><span style="color: #000000;">"</span><span style="color: #000000;">Running:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">+</span><span style="color: #000000;">test);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br></span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addError(Test&nbsp;test,&nbsp;Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fNumberOfErrors.setText(Integer.toString(fTestResult.errorCount()));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appendFailure(</span><span style="color: #000000;">"</span><span style="color: #000000;">Error</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;test,&nbsp;t);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addFailure(Test&nbsp;test,&nbsp;Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fNumberOfFailures.setText(Integer.toString(fTestResult.failureCount()));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appendFailure(</span><span style="color: #000000;">"</span><span style="color: #000000;">Failure</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;test,&nbsp;t);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #0000ff;">&nbsp;&nbsp;&nbsp; public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;endTest(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;setLabelValue(fNumberOfRuns,&nbsp;fTestResult.runCount());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fProgressIndicator.step(fTestResult.wasSuccessful());<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span></div>
<br>可以看到，它将错误信息，异常信息保存在List或者Vector集合内，然后显示在界面上：<br>
<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: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;showErrorTrace()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;index</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fFailureList.getSelectedIndex();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(index&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">-</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Throwable&nbsp;t</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(Throwable)&nbsp;fExceptions.elementAt(index);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(fTraceFrame&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTraceFrame</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TraceFrame();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTraceFrame.setLocation(</span><span style="color: #000000;">100</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">100</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTraceFrame.showTrace(t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTraceFrame.setVisible(</span><span style="color: #0000ff;">true</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;showInfo(String&nbsp;message)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fStatusLine.setFont(PLAIN_FONT);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fStatusLine.setForeground(Color.black);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fStatusLine.setText(message);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;showStatus(String&nbsp;status)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fStatusLine.setFont(BOLD_FONT);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fStatusLine.setForeground(Color.red);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fStatusLine.setText(status);<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br>而Junit中的目标对象(Subject）就是TestResult对象，它有添加观察者的方法：<br><br>
<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Registers&nbsp;a&nbsp;TestListener<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addListener(TestListener&nbsp;listener)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fListeners.addElement(listener);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span></div>
<br>而通知观察者又是怎么做的呢？请看这几个方法，都是循环遍历观察者列表，并调用相应的更新方法：<br><br>
<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>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Adds&nbsp;an&nbsp;error&nbsp;to&nbsp;the&nbsp;list&nbsp;of&nbsp;errors.&nbsp;The&nbsp;passed&nbsp;in&nbsp;exception&nbsp;caused&nbsp;the<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;error.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addError(Test&nbsp;test,&nbsp;Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fErrors.addElement(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TestFailure(test,&nbsp;t));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(Enumeration&nbsp;e&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fListeners.elements();&nbsp;e.hasMoreElements();)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((TestListener)&nbsp;e.nextElement()).addError(test,&nbsp;t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Adds&nbsp;a&nbsp;failure&nbsp;to&nbsp;the&nbsp;list&nbsp;of&nbsp;failures.&nbsp;The&nbsp;passed&nbsp;in&nbsp;exception&nbsp;caused<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;the&nbsp;failure.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addFailure(Test&nbsp;test,&nbsp;AssertionFailedError&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fFailures.addElement(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TestFailure(test,&nbsp;t));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(Enumeration&nbsp;e&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fListeners.elements();&nbsp;e.hasMoreElements();)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((TestListener)&nbsp;e.nextElement()).addFailure(test,&nbsp;t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Registers&nbsp;a&nbsp;TestListener<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addListener(TestListener&nbsp;listener)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fListeners.addElement(listener);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Informs&nbsp;the&nbsp;result&nbsp;that&nbsp;a&nbsp;test&nbsp;was&nbsp;completed.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">synchronized</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;endTest(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(Enumeration&nbsp;e&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fListeners.elements();&nbsp;e.hasMoreElements();)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((TestListener)&nbsp;e.nextElement()).endTest(test);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br><br>使用这个模式后带来的好处：<br>1)上面提到的Subject与Observer的抽象耦合，使JUnit可以支持不同的使用方式<br>2）支持了广播通信，目标对象不关心有多少对象对自己注册，它只是通知注册的观察者<br><br>最后，我实现了一个简单的ConsoleRunner，在控制台执行JUnit,比如我们写了一个简单测试：<br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;junit.samples;<br><br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;junit.framework.</span><span style="color: #000000;">*</span><span style="color: #000000;">;<br><br></span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;*&nbsp;Some&nbsp;simple&nbsp;tests.<br>&nbsp;*&nbsp;<br>&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;SimpleTest&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;TestCase&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;fValue1;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">protected</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;fValue2;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;SimpleTest(String&nbsp;name)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">super</span><span style="color: #000000;">(name);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;setUp()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fValue1&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">2</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fValue2&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">3</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;testAdd()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">double</span><span style="color: #000000;">&nbsp;result&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;fValue1&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;fValue2;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">assert</span><span style="color: #000000;">(result&nbsp;</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;}<br><br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;testEquals()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span style="color: #000000;">12</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span style="color: #000000;">12L</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">12L</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Long(</span><span style="color: #000000;">12</span><span style="color: #000000;">),&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Long(</span><span style="color: #000000;">12</span><span style="color: #000000;">));<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span style="color: #000000;">"</span><span style="color: #000000;">Size</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">12</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;assertEquals(</span><span style="color: #000000;">"</span><span style="color: #000000;">Capacity</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">12.0</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">11.99</span><span style="color: #000000;">,&nbsp;</span><span style="color: #000000;">0.01</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br>}</span></div>
<br>使用ConsoleRunner调用这个测试，代码很简单，不多做解释了：<br>
<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: #0000ff;">package</span><span style="color: #000000;">&nbsp;net.rubyeye.junit.framework;<br><br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.lang.reflect.Method;<br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.ArrayList;<br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.List;<br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;java.util.Vector;<br><br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;junit.framework.Test;<br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;junit.framework.TestListener;<br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;junit.framework.TestResult;<br></span><span style="color: #0000ff;">import</span><span style="color: #000000;">&nbsp;junit.samples.SimpleTest;<br></span><span style="color: #008000;">//</span><span style="color: #008000;">实现观察者接口</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;ConsoleRunner&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;TestListener&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;TestResult&nbsp;fTestResult;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Vector&nbsp;fExceptions;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Vector&nbsp;fFailedTests;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;List&nbsp;fFailureList;<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;ConsoleRunner()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fExceptions&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Vector();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fFailedTests&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Vector();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fFailureList&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ArrayList();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;endTest(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">测试结束：</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;message&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;test.toString();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(fTestResult.wasSuccessful())<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(message&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;测试成功!</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(fTestResult.errorCount()&nbsp;</span><span style="color: #000000;">==</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">1</span><span style="color: #000000;">)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(message&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;had&nbsp;an&nbsp;error</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">else</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(message&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;had&nbsp;a&nbsp;failure</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&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&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;fFailureList.size();&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fFailureList.get(i));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&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&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;fFailedTests.size();&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fFailureList.get(i));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&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&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;fExceptions.size();&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fFailureList.get(i));<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">------------------------</span><span style="color: #000000;">"</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;startTest(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</span><span style="color: #000000;">"</span><span style="color: #000000;">开始测试:</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;test);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;TestResult&nbsp;createTestResult()&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;TestResult();<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;String&nbsp;truncateString(String&nbsp;s,&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;length)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(s.length()&nbsp;</span><span style="color: #000000;">&gt;</span><span style="color: #000000;">&nbsp;length)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;s&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;s.substring(</span><span style="color: #000000;">0</span><span style="color: #000000;">,&nbsp;length)&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;"><img src="http://www.blogjava.net/Images/dot.gif"></span><span style="color: #000000;">"</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">return</span><span style="color: #000000;">&nbsp;s;<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addError(Test&nbsp;test,&nbsp;Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fTestResult.errorCount());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appendFailure(</span><span style="color: #000000;">"</span><span style="color: #000000;">Error</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;test,&nbsp;t);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addFailure(Test&nbsp;test,&nbsp;Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(fTestResult.failureCount());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;appendFailure(</span><span style="color: #000000;">"</span><span style="color: #000000;">Failure</span><span style="color: #000000;">"</span><span style="color: #000000;">,&nbsp;test,&nbsp;t);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;appendFailure(String&nbsp;kind,&nbsp;Test&nbsp;test,&nbsp;Throwable&nbsp;t)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kind&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">:&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;test;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;msg&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;t.getMessage();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(msg&nbsp;</span><span style="color: #000000;">!=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">null</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;kind&nbsp;</span><span style="color: #000000;">+=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">"</span><span style="color: #000000;">:</span><span style="color: #000000;">"</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">+</span><span style="color: #000000;">&nbsp;truncateString(msg,&nbsp;</span><span style="color: #000000;">100</span><span style="color: #000000;">);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fFailureList.add(kind);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fExceptions.addElement(t);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fFailedTests.addElement(test);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;go(String&nbsp;args[])&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Method[]&nbsp;methods&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;SimpleTest.</span><span style="color: #0000ff;">class</span><span style="color: #000000;">.getDeclaredMethods();<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&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&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">0</span><span style="color: #000000;">;&nbsp;i&nbsp;</span><span style="color: #000000;">&lt;</span><span style="color: #000000;">&nbsp;methods.length;&nbsp;i</span><span style="color: #000000;">++</span><span style="color: #000000;">)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">//</span><span style="color: #008000;">取所有以test开头的方法</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;">if</span><span style="color: #000000;">&nbsp;(methods[i].getName().startsWith(</span><span style="color: #000000;">"</span><span style="color: #000000;">test</span><span style="color: #000000;">"</span><span style="color: #000000;">))&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Test&nbsp;test&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;SimpleTest(methods[i].getName());<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTestResult&nbsp;</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;createTestResult();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTestResult.addListener(ConsoleRunner.</span><span style="color: #0000ff;">this</span><span style="color: #000000;">);<br>&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;">执行测试</span><span style="color: #008000;"><br></span><span style="color: #000000;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.run(fTestResult);<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;}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">static</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;main(String&nbsp;args[])&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;ConsoleRunner().go(args);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br><br>}<br></span></div>
<br>  <img src ="http://www.blogjava.net/killme2008/aggbug/108743.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-05 17:19 <a href="http://www.blogjava.net/killme2008/archive/2007/04/05/108743.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>JUnit源码分析（一）——Command模式和Composite模式</title><link>http://www.blogjava.net/killme2008/archive/2007/04/05/108702.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Thu, 05 Apr 2007 07:10:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/04/05/108702.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/108702.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/04/05/108702.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/108702.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/108702.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp; JUnit的源码相比于spring和hibernate来说比较简单，但麻雀虽小，五脏俱全，其中用到了比较多的设计模式。很多人已经在网上分享了他们对JUnit源码解读心得，我这篇小文谈不出什么新意，本来不打算写，可最近工作上暂时无事可做，那就写写吧，结合《设计模式》来看看。<br>&nbsp;&nbsp;&nbsp; 我读的是JUnit3.0的源码，目前JUnit已经发布到4.0版本了，尽管有比较大的改进，但基本的骨架不变，读3.0是为了抓住重点，省去对旁支末节的关注。我们来看看JUnit的核心代码，也就是Junit.framework包，除了4个辅助类（Assert,AssertFailedError,Protectable,TestFailure），剩下的就是我们需要重点关注的了。我先展示一张UML类图：<br><br><img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/junit_core.jpg">&nbsp;&nbsp;&nbsp; 我们先不去关注TestDecorator类（此处是Decorator模式，下篇文章再讲），看看Test接口，以及它的两个实现类TestCase和TestSuite。很明显，此处用到了Command模式，为什么要使用这个模式呢？让我们先来看看什么是Command模式。<br><br><span style="font-weight: bold;">Command模式<br><br></span>Command模式是行为型模式之一<br><br>1.意图：将一个请求封装为一个对象，从而使你可用不同的请求对客户进行参数化；对请求排队或者记录请求日志，以及支持可撤销的操作。<br>2.适用场景：<br>1）抽象出待执行的动作以参数化对象，Command模式是回调函数的面向对象版本。回调函数，我想大家都明白，函数在某处注册，然后在稍后的某个时候被调用。<br>2）可以在不同的时刻指定、排列和执行请求。<br>3）支持修改日志，当系统崩溃时，这些修改可以被重做一遍。<br>4）通过Command模式，你可以通过一个公共接口调用所有的事务，并且也易于添加新的事务。<br><br><br>3。UML图：<br>&nbsp;&nbsp;&nbsp; <img alt="" src="http://www.blogjava.net/images/blogjava_net/killme2008/command.jpg" height="275" width="408"><br><br>4.效果：<br>1）命令模式将调用操作的对象与如何实现该操作的对象解耦。<br>2）将命令当成一个头等对象，它们可以像一般对象那样进行操纵和扩展<br>3）可以将多个命令复合成一个命令，与Composite模式结合使用<br>4）增加新的命令很容易，隔离对现有类的影响<br>5）可以与备忘录模式配合，实现撤销功能。<br><br>&nbsp;&nbsp;&nbsp; 在了解了Command模式之后，那我们来看JUnit的源码，Test接口就是命令的抽象接口，而TestCase和TestSuite是具体的命令<br>
<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;">抽象命令接口</span><span style="color: #008000;"><br></span><span style="color: #0000ff;">package</span><span style="color: #000000;">&nbsp;junit.framework;<br><br></span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;*&nbsp;A&nbsp;&lt;em&gt;Test&lt;/em&gt;&nbsp;can&nbsp;be&nbsp;run&nbsp;and&nbsp;collect&nbsp;its&nbsp;results.<br>&nbsp;*<br>&nbsp;*&nbsp;</span><span style="color: #808080;">@see</span><span style="color: #008000;">&nbsp;TestResult<br>&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">interface</span><span style="color: #000000;">&nbsp;Test&nbsp;{<br><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Counts&nbsp;the&nbsp;number&nbsp;of&nbsp;test&nbsp;cases&nbsp;that&nbsp;will&nbsp;be&nbsp;run&nbsp;by&nbsp;this&nbsp;test.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">int</span><span style="color: #000000;">&nbsp;countTestCases();<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Runs&nbsp;a&nbsp;test&nbsp;and&nbsp;collects&nbsp;its&nbsp;result&nbsp;in&nbsp;a&nbsp;TestResult&nbsp;instance.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run(TestResult&nbsp;result);<br>}<br><br></span><span style="color: #008000;">//</span><span style="color: #008000;">具体命令一</span><span style="color: #008000;"><br></span><span style="color: #000000;"><br></span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">abstract</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">class</span><span style="color: #000000;">&nbsp;TestCase&nbsp;</span><span style="color: #0000ff;">extends</span><span style="color: #000000;">&nbsp;Assert&nbsp;</span><span style="color: #0000ff;">implements</span><span style="color: #000000;">&nbsp;Test&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;the&nbsp;name&nbsp;of&nbsp;the&nbsp;test&nbsp;case<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">final</span><span style="color: #000000;">&nbsp;String&nbsp;fName;<br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp; <img src="http://www.blogjava.net/Images/dot.gif"><img src="http://www.blogjava.net/Images/dot.gif"><br><br>//具体命令二<br><br>public&nbsp;class&nbsp;TestSuite&nbsp;implements&nbsp;Test&nbsp;{<br>&nbsp;&nbsp;&nbsp; &nbsp;<img src="http://www.blogjava.net/Images/dot.gif"></span></div>
<br>由此带来的好处：<br>1.客户无需使用任何条件语句去判断测试的类型，可以用统一的方式调用测试和测试套件，解除了客户与具体测试子类的耦合<br>2.如果要增加新的TestCase也很容易，实现Test接口即可，不会影响到其他类。<br>3.很明显，TestSuite是通过组合多个TestCase的复合命令，这里使用到了Composite模式（组合）<br>4.尽管未实现redo和undo操作，但将来也很容易加入并实现。<br><br>&nbsp;&nbsp;&nbsp; 我们上面说到TestSuite组合了多个TestCase，应用到了Composite模式，那什么是Composite模式呢？具体来了解下。<br><br><span style="font-weight: bold;">Composite模式<br><br></span>composite模式是对象结构型模式之一。<span style="font-weight: bold;"><br></span>1.意图：将对象组合成树形结构以表示&#8220;部分——整体&#8221;的层次结构。使得用户对单个对象和组合结构的使用具有一致性。<br><br>2.适用场景：<br>1）想表示对象的部分-整体层次<br>2）希望用户能够统一地使用组合结构和单个对象。具体到JUnit源码，我们是希望用户能够统一地方式使用TestCase和TestSuite<br><br>3.UML图：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <img alt=""  src="http://www.blogjava.net/images/blogjava_net/killme2008/composite.gif"><br><br>图中单个对象就是树叶（Leaf），而组合结构就是Compoiste，它维护了一个Leaf的集合。而Component是一个抽象角色，给出了共有接口和默认行为，也就是JUnit源码中的Test接口。<br><br>4.效果：<br>1）定义了基本对象和组合对象的类层次结构，通过递归可以产生更复杂的组合对象<br>2）简化了客户代码，客户可以使用一致的方式对待单个对象和组合结构<br>3）添加新的组件变的很容易。但这个会带来一个问题，你无法限制组件中的组件，只能靠运行时的检查来施加必要的约束条件<br><br>&nbsp;&nbsp;&nbsp; 具体到JUnit源码，单个对象就是TestCase，而复合结构就是TestSuite，Test是抽象角色只有一个run方法。TestSuite维护了一个TestCase对象的集合fTests：<br><br>
<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;">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">private</span><span style="color: #000000;">&nbsp;Vector&nbsp;fTests</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">new</span><span style="color: #000000;">&nbsp;Vector(</span><span style="color: #000000;">10</span><span style="color: #000000;">);&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">/**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Adds&nbsp;a&nbsp;test&nbsp;to&nbsp;the&nbsp;suite.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;addTest(Test&nbsp;test)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fTests.addElement(test);<br>&nbsp;&nbsp;&nbsp;&nbsp;}<br></span><span style="color: #008000;">&nbsp;&nbsp;&nbsp; /**</span><span style="color: #008000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;*&nbsp;Runs&nbsp;the&nbsp;tests&nbsp;and&nbsp;collects&nbsp;their&nbsp;result&nbsp;in&nbsp;a&nbsp;TestResult.<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #008000;">*/</span><span style="color: #000000;"><br>&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">public</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">void</span><span style="color: #000000;">&nbsp;run(TestResult&nbsp;result)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">for</span><span style="color: #000000;">&nbsp;(Enumeration&nbsp;e</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;tests();&nbsp;e.hasMoreElements();&nbsp;)&nbsp;{<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">if</span><span style="color: #000000;">&nbsp;(result.shouldStop()&nbsp;)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: #0000ff;">break</span><span style="color: #000000;">;<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Test&nbsp;test</span><span style="color: #000000;">=</span><span style="color: #000000;">&nbsp;(Test)e.nextElement();<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;test.run(result);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<br>&nbsp;&nbsp;&nbsp;&nbsp;}</span></div>
<br>当执行run方法时遍历这个集合，调用里面每个TestCase对象的run()方法，从而执行测试。我们使用的时候仅仅需要把TestCase添加到集合内，然后用一致的方式（run方法）调用他们进行测试。<br><br>考虑使用Composite模式之后带来的好处：<br>1）JUnit可以统一地处理组合结构TestSuite和单个对象TestCase，避免了条件判断，并且可以递归产生更复杂的测试对象<br>2）很容易增加新的TestCase。<br><br><br>参考资料：《设计模式——可复用面向对象软件的基础》<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 《JUnit设计模式分析》 刘兵<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; JUnit源码和文档<br><br><br><br><span style="font-weight: bold;"></span><br><br><br><br><br><span style="font-weight: bold;"></span><br>&nbsp;&nbsp;&nbsp;&nbsp; <br><img src ="http://www.blogjava.net/killme2008/aggbug/108702.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-04-05 15:10 <a href="http://www.blogjava.net/killme2008/archive/2007/04/05/108702.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>创建型模式摘记</title><link>http://www.blogjava.net/killme2008/archive/2007/03/17/104485.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 17 Mar 2007 09:01:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/03/17/104485.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/104485.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/03/17/104485.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/104485.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/104485.html</trackback:ping><description><![CDATA[    系统的演化应当依赖于组合，而不是继承；这就提出了将类的实例化委托给一个对象的要求，因此创建型模式将变的越来越重要。<br /><div style="text-indent: 21pt;">创建型模式属于对象创建模型。所谓对象创建模型就是说将实例化的工作委托给另一个对象来做。与之相对应的是类创建模型，这是一种通过继承改变被实例化的类。</div><div><span>       </span>创建型模式有两个重要的特点：</div><div style="margin-left: 39pt; text-indent: -18pt;"><span>1） </span>客户不知道创建的具体类是什么（除非看源代码）</div><div style="margin-left: 39pt; text-indent: -18pt;"><span>2） </span>隐藏了类的实例是如何被创建和放在一起的</div><br />一。抽象工厂模式<br />1.意图：提供一个创建<b>一系列</b>相关或相互依赖对象的接口，而无需指定它们的具体的类。<br />2.适用场景：<br />1)一个系统要独立于它的产品的创建、组合和表示时<br />2）一个系统要由多个产品系列中的一个来配置时<br />3）当你要强调一系列相关的产品对象的设计以便进行联合使用时<br />4）当你提供一个产品类库，而只想显示它们的接口而不是实现时<br /><br />3.UML图——结构<br /><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/sheismylife/07cbd5dfdbdd4027a1ed513e503b1d6f.png" /><br />4.效果：<br />1）分离了具体的类，通过抽象接口将客户与具体的类分离<br />2）易于交换产品系列<br />3）有利于产品的一致性<br />4）难以支持新种类的产品，比如我们现在有一个ProductC产品，我们需要增加类AbstractProductC，增加AbstractFactory::
CreanteProductC方法，并且两个产品系列的实际创建者ConCreateFactory1、ConCreateFactor2都要实现该方
法。<div>可以通过给方法加参数的方式来指明创建的是什么产品，这样客户代码就无需改变，只要传递不同的参数。AbstractFactory类只需要提供一个CreateProduct(const string&amp; name)方法即可。<br /><br />5.代码实现，以《深入浅出设计模式(java C#)》的动物工厂为例：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System;<br /></span><span style="color: rgb(0, 0, 255);">namespace</span><span style="color: rgb(0, 0, 0);"> AnimalWorld<br />{<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 抽象大陆工厂</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> ContinentFactory<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Herbivore CreateHerbivore();<br />        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Carnivore CreateCarnivore();<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">非洲大陆,有角马，狮子</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> AfricaFactory : ContinentFactory<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Herbivore CreateHerbivore()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Wildebeest();<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Carnivore CreateCarnivore()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Lion();<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 美洲大陆,有狼,野牛</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> AmericaFactory : ContinentFactory<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Herbivore CreateHerbivore()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Bison();<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Carnivore CreateCarnivore()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Wolf();<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">食草动物"</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Herbivore<br />    {<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">肉食动物"</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Carnivore<br />    {<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">猎食食草动物的方法</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Eat( Herbivore h );<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">角马</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Wildebeest : Herbivore<br />    {<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">狮子"</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Lion : Carnivore<br />    {<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">重载猎食食草动物的方法</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Eat( Herbivore h )<br />        {<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> eats </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> h );<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">野牛</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Bison : Herbivore<br />    {<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">狼</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Wolf : Carnivore<br />    {<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">重载猎食食草动物的方法</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Eat( Herbivore h )<br />        {<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> eats </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> h );<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">动物世界类</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> AnimalWorld<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> Herbivore herbivore;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> Carnivore carnivore;<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 创建两种动物分类</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> AnimalWorld( ContinentFactory factory )<br />        {<br />            carnivore </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> factory.CreateCarnivore();<br />            herbivore </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> factory.CreateHerbivore();<br />        }<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">运行食物链</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> RunFoodChain()<br />        {<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">肉食动物猎食食草动物</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            carnivore.Eat( herbivore );<br />        }<br />    }<br />    </span><span style="color: rgb(128, 128, 128);">///</span><span style="color: rgb(0, 128, 0);"> </span><span style="color: rgb(128, 128, 128);">&lt;summary&gt;</span><span style="color: rgb(0, 128, 0);"><br />    </span><span style="color: rgb(128, 128, 128);">///</span><span style="color: rgb(0, 128, 0);"> 抽象工厂模式客户应用测试<br />    </span><span style="color: rgb(128, 128, 128);">///</span><span style="color: rgb(0, 128, 0);"> </span><span style="color: rgb(128, 128, 128);">&lt;/summary&gt;</span><span style="color: rgb(128, 128, 128);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> GameApp<br />    {<br />        [STAThread]<br />        </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Main(</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">[] args)<br />        {<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">创造并运行非洲动物世界</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            ContinentFactory africa </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> AfricaFactory();<br />            AnimalWorld world </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> AnimalWorld( africa );<br />            world.RunFoodChain();<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">创造并运行美洲动物世界</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            ContinentFactory america </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> AmericaFactory();<br />            world </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> AnimalWorld( america );<br />            world.RunFoodChain();<br />            Console.Read();<br />        }<br /><br />    }<br />}<br /></span></div><br />二。Builder模式<br />1.意图：将一个<b>复杂对象</b>的构建与它的表示相分离，使得同样的构建过程可以创建不同的表示（或者说产品）<br /><br />2.适用场景：<br />1）当创建复杂对象的算法应该独立于改对象的组成部分以及它们的装配方式时<br />2）当构造过程必须允许被构造的对象有不同的表示时<br /><br />3.UML图——结构<br /><br /><img src="file:///C:/DOCUME%7E1/Admin/LOCALS%7E1/Temp/moz-screenshot-2.jpg" alt="" /><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/sheismylife/c9bff79b4fbd48859316f43e1b61a265.png" /><br /><img src="file:///C:/DOCUME%7E1/Admin/LOCALS%7E1/Temp/moz-screenshot.jpg" alt="" /><img src="file:///C:/DOCUME%7E1/Admin/LOCALS%7E1/Temp/moz-screenshot-1.jpg" alt="" />Director接受一个Builder子类对象，完成创建过程，并通知Builder对象返回以及构造好的产品。<br /><br />4.效果：<br />1）可以使你改变一个对象的内部表示<br />2）构造代码和表示代码分开<br />3）可以对构造过程进行更精细的控制<br /><br />5。实现：以一个车辆建造过程为例（C#)<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System;<br /><br /></span><span style="color: rgb(0, 0, 255);">namespace</span><span style="color: rgb(0, 0, 0);"> CarShop<br />{<br />    </span><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System;<br />    </span><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System.Collections;<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">指挥者,Director</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Shop{<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Construct( VehicleBuilder vehicleBuilder ){<br />            vehicleBuilder.BuildFrame();<br />            vehicleBuilder.BuildEngine();<br />            vehicleBuilder.BuildWheels();<br />            vehicleBuilder.BuildDoors();<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">/*</span><span style="color: rgb(0, 128, 0);"> "Builder 建造者",Builder<br />    抽象建造者具有四种方法<br />    装配框架<br />    装配发动机<br />    装配轮子<br />    装配车门<br />    </span><span style="color: rgb(0, 128, 0);">*/</span><span style="color: rgb(0, 0, 0);"><br />    </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> VehicleBuilder<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">protected</span><span style="color: rgb(0, 0, 0);"> Vehicle vehicle;<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">返回建造完成的车辆</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Vehicle Vehicle{<br />            </span><span style="color: rgb(0, 0, 255);">get</span><span style="color: rgb(0, 0, 0);">{ </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> vehicle; }<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildFrame();<br />        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildEngine();<br />        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildWheels();<br />        </span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildDoors();<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">具体建造者-摩托车车间</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> MotorCycleBuilder : VehicleBuilder<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildFrame(){<br />            vehicle </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Vehicle( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">摩托车</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> );<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">MotorCycle Frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildEngine(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">engine</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">500 cc</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildWheels(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">wheels</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildDoors(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doors</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">具体建造者-轿车车间</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> CarBuilder : VehicleBuilder<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildFrame(){<br />            vehicle </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Vehicle( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">轿车</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> );<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Car Frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildEngine(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">engine</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">2500 cc</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildWheels(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">wheels</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildDoors(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doors</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 具体建造者-单脚滑行车车间</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> ScooterBuilder : VehicleBuilder<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildFrame(){<br />            vehicle </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Vehicle( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">单脚滑行车</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> );<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">Scooter Frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildEngine(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">engine</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">none</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildWheels(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">wheels</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br /><br />        </span><span style="color: rgb(0, 0, 255);">override</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BuildDoors(){<br />            vehicle[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doors</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />    }<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">车辆产品类</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Vehicle<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);"> type;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> Hashtable parts </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Hashtable();<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">筑构函数,决定类型</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Vehicle( </span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);"> type ){<br />            </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.type </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> type;<br />        }<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">索引</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">object</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">[ </span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);"> key ]{<br />            </span><span style="color: rgb(0, 0, 255);">get</span><span style="color: rgb(0, 0, 0);">{ </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> parts[ key ]; }<br />            </span><span style="color: rgb(0, 0, 255);">set</span><span style="color: rgb(0, 0, 0);">{ parts[ key ] </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> value; }<br />        }<br />        </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">显示方法</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Show()<br />        {<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">\n---------------------------</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">);<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">车辆类类型: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> type );<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> 框架 : </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> parts[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">frame</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] );<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> 发动机 : </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> parts[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">engine</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">] );<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> #轮子数: </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> parts[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">wheels</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">] );<br />            Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> #车门数 : </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> parts[ </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">doors</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> ] );<br />        }<br />    }<br />    </span><span style="color: rgb(128, 128, 128);">///</span><span style="color: rgb(0, 128, 0);"> </span><span style="color: rgb(128, 128, 128);">&lt;summary&gt;</span><span style="color: rgb(0, 128, 0);"><br />    </span><span style="color: rgb(128, 128, 128);">///</span><span style="color: rgb(0, 128, 0);"> 建造者模式应用测试<br />    </span><span style="color: rgb(128, 128, 128);">///</span><span style="color: rgb(0, 128, 0);"> </span><span style="color: rgb(128, 128, 128);">&lt;/summary&gt;</span><span style="color: rgb(128, 128, 128);"><br /></span><span style="color: rgb(0, 0, 0);">     </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> CarShop<br />    {<br />        [STAThread]<br />        </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Main(</span><span style="color: rgb(0, 0, 255);">string</span><span style="color: rgb(0, 0, 0);">[] args)<br />        {<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 创造车间及车辆建造者</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            Shop shop </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Shop();<br />            VehicleBuilder b1 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ScooterBuilder();<br />            VehicleBuilder b2 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> CarBuilder();<br />            VehicleBuilder b3 </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MotorCycleBuilder();<br />            </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);"> 筑构并显示车辆</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">            shop.Construct( b1 );<br />            b1.Vehicle.Show();<br />            shop.Construct( b2 );<br />            b2.Vehicle.Show();<br />            shop.Construct( b3 );<br />            b3.Vehicle.Show();<br />            Console.Read();<br /><br />        }<br />    }<br />}<br /></span></div><br /><br /><strong></strong>三。Factory Method模式<br />1.意图：定义一个用于创建对象的接口，让子类决定实例化具体的哪一个类。<br />2.适用场景：<br />1）当一个类不知道它所必须创建的对象的类的时候，让子类来决定<br />2）当一个类希望由它的子类来决定它所创建的对象的时候<br /><br />3。UML图——结构：<br /><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/sheismylife/638ccee7f75e4632a78bdda0a084690b.png" /><br />4.效果：<br />1）为子类提供回调函数<br />2）连接平行的类层次<br /><div style="margin-left: 18pt; text-indent: -18pt;"><span>3） </span>创建函数可以接收参数来决定创建什么产品</div><div>4）Factory Method容易导致创建过多的Creator的子类以对应不同的产品，这个方法可以通过模板技术来解决<br /><br />6.实现，手机工厂，产品可能是Nokia，也可能是Motorola<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System;<br /></span><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System.Collections.Generic;<br /></span><span style="color: rgb(0, 0, 255);">using</span><span style="color: rgb(0, 0, 0);"> System.Text;<br /><br /></span><span style="color: rgb(0, 0, 255);">namespace</span><span style="color: rgb(0, 0, 0);"> HandPhone<br />{<br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">手机接口</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);"> Mobile<br />    {<br />         </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> call();<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">手机工厂接口</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">interface</span><span style="color: rgb(0, 0, 0);"> MobileFactory<br />    {<br />          Mobile createMobile();<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">Nokia</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Nokia:Mobile<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> call()<br />        {<br />            Console.WriteLine(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">This is a {0} phone</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.GetType().Name);<br />        }<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">Motorola</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Motorola : Mobile<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> call()<br />        {<br />            Console.WriteLine(</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">This is a {0} phone</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">, </span><span style="color: rgb(0, 0, 255);">this</span><span style="color: rgb(0, 0, 0);">.GetType().Name);<br />        }<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">Motorola工厂</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> MotorolaFactory : MobileFactory<br />    {<br />         </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Mobile createMobile()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Motorola();<br />        }<br />    }<br /><br />    </span><span style="color: rgb(0, 128, 0);">//</span><span style="color: rgb(0, 128, 0);">Nokia工厂</span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">    </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> NokiaFactroy : MobileFactory<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> Mobile createMobile()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Nokia();<br />        }<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Client<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> Main(String []args)<br />        {<br />            MobileFactory factory</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">;<br />            Mobile mobile</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">;<br /><br />            factory</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> NokiaFactroy();<br />            mobile</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">factory.createMobile();<br />            mobile.call();<br /><br />            factory</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> MotorolaFactory();<br />            mobile</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">factory.createMobile();<br />            mobile.call();<br />            <br />        }<br />    }<br /><br />}<br /></span></div><br />四。Prototype模式<br /><br />1.意图：通过原型实例指定创建对象的种类，并通过拷贝这些原型来创建新的对象<br /><br />2.适用场景：<br />1）要实例化的类是在运行时刻指定的，比如动态装载<br />2）为了避免创建一个与产品层次平行的工厂类层次<br />3）当一个类的实例只能有几个不同的状态组合中的一种时，建立相应数目的原型并克隆它们可能比每次用合适的状态手工化该类更方便一些。<br /><br />3.UML图——结构：<br /><img src="http://p.blog.csdn.net/images/p_blog_csdn_net/sheismylife/9767a24f6e804101a9c0ae875105f950.png" /><br /><br /></div><br />4.效果：<br />1）运行时动态增加或者删除产品<br />2）减少子类的构造数目<br />3）用类动态配置应用<br />4）动态指定新的对象，通过改变结构或者值<br />5）缺陷在于每一个Prototype的子类都需要实现clone操作<br /><br />5。实现,无论java还是C#都从语言层次内置了对prototype模式的支持。具体不再详述。<br /><br />五。singleton模式<br />1。意图：保证一个类仅有一个实例，并提供一个访问它的全局访问点<br /><br />2.适用场景：<br />1）当需要类只有一个实例，并且客户只能通过一个全局点去访问它<br />2）当这个唯一实例应该是通过子类化可扩展的，并且客户应该无需更改代码就能使用扩展的实例<br /><br />3.UML图：略<br /><br />4.效果：<br />1）对唯一实例的受控访问<br />2）缩小命名空间<br />3）允许对操作和表示的细化<br />4）允许可变数目的实例<br /><br />5实现，关于singleton在java多线程环境下的实现，请见讨论《<a id="viewpost1_TitleUrl" class="postTitle2" href="http://www.cnblogs.com/AllenYoung/archive/2006/04/14/375144.html">当Singleton遇到multi-threading</a>》，C#对singleton多线程环境下的能够正确实现Double-checked模式：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">sealed</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Singleton<br />{<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">volatile</span><span style="color: rgb(0, 0, 0);"> Singleton instance;<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">object</span><span style="color: rgb(0, 0, 0);"> syncRoot </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Object();<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> Singleton() {}<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> Singleton Instance<br />    {<br />        </span><span style="color: rgb(0, 0, 255);">get</span><span style="color: rgb(0, 0, 0);"> <br />        {<br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (instance </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">) <br />            {<br />                </span><span style="color: rgb(0, 0, 255);">lock</span><span style="color: rgb(0, 0, 0);"> (syncRoot) <br />                {<br />                    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (instance </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">) <br />                        instance </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Singleton();<br />                }<br />            }<br /><br />            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> instance;<br />        }<br />    }<br />}</span></div><br /><br />本文仅作速查记忆用，摘记于《设计模式——可复用面向对象软件基础》和《深入浅出设计模式（java C#)》两书<br /><br /></div><img src ="http://www.blogjava.net/killme2008/aggbug/104485.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-03-17 17:01 <a href="http://www.blogjava.net/killme2008/archive/2007/03/17/104485.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>《设计模式精解》读后感</title><link>http://www.blogjava.net/killme2008/archive/2007/03/03/101592.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Sat, 03 Mar 2007 02:41:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/03/03/101592.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/101592.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/03/03/101592.html#Feedback</comments><slash:comments>7</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/101592.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/101592.html</trackback:ping><description><![CDATA[    模式一直是J2EE领域的热门话题。两年前，对刚开始自学java并且到处碰壁的我，一本在图书馆借的《java与模式》看的我云里雾里，尽管心里面觉的他讲的很有道理，可对于没有实际项目经验的我，真正的理解和应用还很远很远。转眼工作快一年多了了，也做了几个不大不小的项目，尽管还只是个代码工人水准的，但是对于模式的兴趣越发浓厚，于是从书堆里找出来买了好久的GOF《设计模式》。这本书是圣经级别了，可我对C++的了解有限（虽然在学校里还是狠狠啃过好几本大部头，现在忘光了），而且这本圣经对初学者似乎不太友好，对模式也以罗列各条目为主，例子失当。于是买了《设计模式精解》，看china-pub的书评都说对初学者很有用，而且翻译的人也是我很佩服的gigix。<br />    在春节期间读完了这本书，本书详细介绍了13种常见的设计模式，以一个实际问题引出了对面向对象新观点和设计模式的讨论，在介绍完所有的模式后，更难能可贵的是作者详细介绍了自己对模式的使用经验（使用共同点/变化点分析，使用分析矩阵等），整本书读下来令人心旷神怡。<br />    我们为什么要学习设计模式呢？总之是为了获得可以复用和容易扩展的解决方案，建立通用术语以方便团队内的沟通交流，另外，模式能让你以更高的层次或者说视角去观察问题，这样的视角将你从过早处理细节的泥潭中解放出来。模式本身就是对如何创建优良面向对象设计策略的实现：<br />    1.针对接口编程<br />    2.优先使用对象组合，而不是类继承<br />    3.发现并封装变化点<br />     你可以在每一个模式的背后或者每一个优秀设计的背后看到这些原则的影子。比如abstract factory、adapter、strategy体现了针对接口编程，composite、bridge体现了优先使用组合而不是继承等。<br />    <br />    作者解释了面向对象的新观点:<br />    <br />                原来的观点                新的观点<br /><br />对象           伴随有方法的数据            拥有责任的实体，或者说拥有特定行为的实体    <br /><br /><br />封装          数据隐藏                    各种形式的封装，1.数据的封装，2.方法的封装<br />                                           3.父类对子类的隐藏   4.其他对象的封装<br /><br />继承          特化和复用                   对象分类的一种方法<br /><br />    这些观点其实并不新，Martin Fowler提出了软件开发过程中的三种视觉：概念、规格和实现，过去我们对面向对象的观点来自于实现的角度(代码的角度）去观察，而新的观点只是从概念的角度重新观察面向对象设计。<br />    深入到具体模式的讨论，记录一些需要注意的问题：<br />1.Adapter与Facade模式的区别<br />它们都是包装器，但是两者也有细微的区别:<br />.两个模式中，我们都有已经存在的类（或者说系统）<br />.Facade模式中，我们无需针对接口编程；而Adapter模式我们必须针对接口编程<br />.Adapter模式通常是为了保持多态，而Facade模式对此不感兴趣<br />.动机不同，Facade模式是为了简化接口，而Adapter模式是针对一个现存的接口编程<br />结论：Facade模式简化接口，而Adapter模式将接口转换成另一个现有的接口<br /><br />2.Bridge模式的理解<br />Bridge模式的意图是将抽象部分与它的实现部分分离，使它们可以独立的变化。这里的关键点是需要理解“实现部分”，如果把“实现部分”看成“对象外部、被对象使用的某种东西”，此模式就很好理解了。我们将变化转移到一个使用或者拥有变化的对象（此对象是指抽象类的对象和用来实现抽象类的派生类的对象）。当出现继承的类爆炸情况时，也许你该考虑此模式的应用场景了。此模式的UML图<br /><img src="http://www.blogjava.net/images/blogjava_net/killme2008/Bridge1.jpg" alt="Bridge1.jpg" border="0" height="185" width="553" /><br /><br /><br />3.Observer模式，实现自己的观察者模式也是很简单，不过java已经内置了对此模式的支持。java.util.Observer和java.util.Observable是此模式的一个实现版本，实际应用中你所需要做的只是实现Observer接口，和继承Observable类<br /><br />4.Decorator模式是为现有的功能动态添加附加功能的一种方法，UML图如下<br /><img src="http://www.blogjava.net/images/blogjava_net/killme2008/ShowImg.jpg" alt="ShowImg.jpg" border="0" height="288" width="391" /><br />java的IO库是典型的应用实现，java.io.InputStream和java.io.OutputStream就是图中的Component接口，FilterInputStream继承InputStream（也就是图中的Decorator，装饰器），其他的如ByteArrayInputStream、FileInputStream等直接继承自InputStream的类就是被装饰对象，而继承FilterInputStream的就是各式各样的装饰者。<br /><br />5.Strategy模式是一种定义算法家族的方法，所有的算法都做相同的工作，它们只是拥有不同的实现。当你的代码中出现了很多switch或者if else的语句，你应该考虑此模式。Strategy模式带来的缺点是类的数量的增加，在java中可以通过将实现类作为嵌套类放在Strategy抽象类中来解决。<br /><br />6.singleton模式的实现<br />单线程应用：<br />第一种：静态初始化<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Singleton {<br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> Singleton() {<br />    }<br /><br />    </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> Singleton instance </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Singleton();<br /><br />    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> Singleton getInstance() {<br />        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> instance;<br />    }<br />}</span></div><br />第二种：lazy loading<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">   Singleton   {    <br />  　　</span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">   Singleton   instance   </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">;  <br />   <br />  　　</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 0);">Singleton   getInstance()   {  <br /></span><span style="color: rgb(0, 128, 0);"></span><span style="color: rgb(0, 128, 0);"><br /></span><span style="color: rgb(0, 0, 0);">  　　</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">   (instance</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">)  <br />  　　　　instance＝</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">   Singleton();  <br />  　　</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">   instance;   　　}    <br />   <br />  }  </span></div><br />多线程环境下：在C++中安全的Double-Checked Locking模式，在java中是不安全的，详细原因与java的内存管理模型有关，请见dreamstone的文章<a href="/dreamstone/archive/2006/11/04/79026.html">《java中的模式——单态》</a><br />安全的实现方法是使用同步：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Singleton {  <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">   <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">  </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> Singleton instance;  <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">   <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">   </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">synchronized</span><span style="color: rgb(0, 0, 0);"> Singleton getInstance() {  <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">     </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> (instance </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">null</span><span style="color: rgb(0, 0, 0);">)  <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">       instance </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Singleton();  <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">     </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> instance;  <br />   </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">   }  <br />  </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);">   <br />  </span><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);"> }  </span></div><br />《Effective Java》中提到的另一种写法<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> Singleton {<br /><br />  </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);"> SingletonHolder {<br />    </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> Singleton instance </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Singleton();<br />  }<br /><br />  </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">static</span><span style="color: rgb(0, 0, 0);"> Singleton getInstance() {<br />    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);"> SingletonHolder.instance;<br />  }<br /><br />}</span></div><br />    在介绍完13个模式之后，作者提出了 一种称为分析矩阵的方法，详细讨论不是这篇短文能说的完，有兴趣请找来此书的电子版看看。简单来讲，先从问题领域中分析出所有的变化点和共同点，观察每一种必须实现的功能并作为矩阵的行，而矩阵中的列表示特定情况中的特定实现；然后观察行，并根据场景探讨使用合适的模式；最后观察列，从整体上考虑整个问题的模式的使用。在出现的概念的场景中添加新的概念来进行设计。<br /><br />    最后，作者总结了面向对象的原则：<br />.“对象”是负有定义良好的责任的东西<br />.对象对自己负责<br />.封装意味着<br />    ——数据隐藏<br />    ——类隐藏（藏在抽象类或者接口后面）<br />    ——实现隐藏（变化封装为对象进行引用）<br />.使用共同点/变化点分析抽象出行为和数据中的变化点<br />.针对接口编程<br />.把继承考虑为一种封装变化的方法，而不是为现有的对象制造特殊情况<br />.将变化点封装在一个类中，并使之与其他变化点相分离<br />.力求松耦合<br />.力求高内聚<br />.绝对细心地应用“一次并且只有一次”规则（只在一个地方实现一条规则） <br />     书本只是提供了模式的介绍和参照，真正的应用还是要靠自己日常工作中的观察和体验，我将继续在工作中理解并贯彻这些原则。       <br /><img src ="http://www.blogjava.net/killme2008/aggbug/101592.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-03-03 10:41 <a href="http://www.blogjava.net/killme2008/archive/2007/03/03/101592.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>使用Annotation设计持久层</title><link>http://www.blogjava.net/killme2008/archive/2007/02/06/98239.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 06 Feb 2007 04:24:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/02/06/98239.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/98239.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/02/06/98239.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/98239.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/98239.html</trackback:ping><description><![CDATA[ 这篇文章的想法来自于过去的两篇文章：《设计自己的MVC框架》《设计模式之事务处理》<br />链接：<br />http://www.javaresearch.org/article/59935.htm<br />http://www.javaresearch.org/article/59043.htm<br /><br /><br />代码下载同样在www.126.com的邮箱里，用户名 sharesources 密码 javafans<br /><br />    本文只是学习性质的文章，我一开始的想法就是修改《设计模式之事务处理》，提供Annotation来提供事务支持，支持到方法级别。通过引入一个 @Transaction标注，如果被此标注的方法将自动享受事务处理。目的是学习下Annotation和加深下对声明式事务处理的理解。<br /><br />    Annotation是JDK5引入的新特性，现在越来越多的框架采用此特性来代替烦琐的xml配置文件，比如hibernate,ejb3, spring等。对Annotation不了解，请阅读IBM网站上的文章，还有推荐javaeye的Annotation专栏：http: //www.javaeye.com/subject/Annotation<br /><br />    代码的示例是一个简单的用户管理例子。<br /><br />    首先，环境是mysql+jdk5+myeclipse5+tomcat5，在mysql中建立一张表adminusers:<br />    create table adminusers(id int(10) auto_increment not null primary key,<br />     name varchar(10) not null,<br />     password varchar(10) not null,<br />     user_type varchar(10));<br />    然后在tomcat下建立一个数据源，把代码中的strutslet.xml拷贝到tomcat安装目录下的 /conf/Catalina/localhost目录里，请自行修改文件中的数据库用户名和密码，以及数据库名称。另外，把mysql的 jdbc驱动拷贝到tomcat安装目录下的common/lib目录。这样数据源就建好了。在web.xml中引用：<br /><br />   &lt;resource-ref&gt;<br />        &lt;description&gt;DB Connection&lt;/description&gt;<br />        &lt;res-ref-name&gt;jdbc/test&lt;/res-ref-name&gt;<br />        &lt;res-type&gt;javax.sql.DataSource&lt;/res-type&gt;<br />        &lt;res-auth&gt;Container&lt;/res-auth&gt;<br />    &lt;/resource-ref&gt;<br />    <br />    我的例子只是在《设计模式之事务处理》的基础上改造的，在那篇文章里，我讲解了自己对声明式事务处理的理解，并利用动态代理实现了一个 TransactionWrapper(事务包装器)，通过业务代理工厂提供两种版本的业务对象：经过事务包装的和未经过事务包装的。我们在默认情况下包装业务对象中的所有方法，但实际情况是，业务对象中的很多方法不用跟数据库打交道，它们根本不需要包装在一个事务上下文中，这就引出了，我们为什么不提供一种方式来配置哪些方法需要事务控制而哪些并不需要？甚至提供事务隔离级别的声明？很自然的想法就是提供一个配置文件，类似spring式的事务声明。既然JDK5已经引入Annotation，相比于配置文件的烦琐和容易出错，我们定义一个@Transaction的annotation来提供此功能。<br /><br />    看下Transaction.java的代码：<br />    package com.strutslet.db;<br /><br />    import java.lang.annotation.Documented;<br />    import java.lang.annotation.ElementType;<br />    import java.lang.annotation.Retention;<br />    import java.lang.annotation.RetentionPolicy;<br />    import java.lang.annotation.Target;<br />    import java.sql.Connection;<br /><br />    @Target(ElementType.METHOD)<br />    @Retention(RetentionPolicy.RUNTIME)<br />    @Documented<br />    public @interface Transaction {<br />       //事务隔离级别，默认为read_committed<br />       public int level() default Connection.TRANSACTION_READ_COMMITTED    ;<br />    }<br /><br />@Transaction 标注只有一个属性level，level表示事务的隔离级别，默认为Read_Committed（也是一般JDBC驱动的默认级别，JDBC驱动默认级别一般于数据库的隔离级别一致）。 @Target(ElementType.METHOD)表示此标注作用于方法级别， @Retention(RetentionPolicy.RUNTIME)表示在运行时，此标注的信息将被加载进JVM并可以通过Annotation的 API读取。我们在运行时读取Annotation的信息，根据隔离级别和被标注的方法名决定是否将业务对象的方法加进事务控制。我们只要稍微修改下 TransactionWrapper:<br /><br />//TransactionWrapper.java<br />package com.strutslet.db;<br /><br />import java.lang.annotation.Annotation;<br />import java.lang.reflect.InvocationHandler;<br />import java.lang.reflect.Method;<br />import java.lang.reflect.Proxy;<br />import java.sql.Connection;<br />import java.sql.SQLException;<br /><br />import com.strutslet.exception.SystemException;<br /><br />public class TransactionWrapper {<br /><br />    <br />    public static Object decorate(Object delegate) {<br />        return Proxy.newProxyInstance(delegate.getClass().getClassLoader(),<br />                delegate.getClass().getInterfaces(), new XAWrapperHandler(<br />                        delegate));<br />    }<br /><br />    static final class XAWrapperHandler implements InvocationHandler {<br />        private final Object delegate;<br /><br />        XAWrapperHandler(Object delegate) {<br />            // Cache the wrapped delegate, so we can pass method invocations<br />            // to it.<br />            this.delegate = delegate;<br />        }<br /><br />        public Object invoke(Object proxy, Method method, Object[] args)<br />                throws Throwable {<br />            Object result = null;<br />            Connection con = ConnectionManager.getConnection();<br />            //得到Transaction标注 <br />            Transaction transaction = method.getAnnotation(Transaction.class);<br /><br />            //如果不为空，说明代理对象调用的方法需要事务控制。<br />            if (transaction != null) {<br />                // System.out.println("transaction.." + con.toString());<br />                // 得到事务隔离级别信息<br />                int level = transaction.level();<br />                try {<br />                    if (con.getAutoCommit())<br />                        con.setAutoCommit(false);<br />                    //设置事务隔离级别<br />                    con.setTransactionIsolation(level);<br />                    //调用原始对象的业务方法<br />                    result = method.invoke(delegate, args);<br />                    con.commit();<br />                    con.setAutoCommit(true);<br />                } catch (SQLException se) {<br />                    // Rollback exception will be thrown by the invoke method<br />                    con.rollback();<br />                    con.setAutoCommit(true);<br />                    throw new SystemException(se);<br />                } catch (Exception e) {<br />                    con.rollback();<br />                    con.setAutoCommit(true);<br />                    throw new SystemException(e);<br />                }<br />            } else {<br />                result = method.invoke(delegate, args);<br />            }<br /><br />            return result;<br />        }<br />    }<br />}<br /><br />现在，看下我们的UserManager业务接口，请注意，我们是使用动态代理，只能代理接口，所以要把@Transaction标注是接口中的业务方法（与EJB3中的Remote,Local接口类似的道理）:<br />package com.strutslet.demo.service;<br /><br />import java.sql.SQLException;<br /><br />import com.strutslet.db.Transaction;<br />import com.strutslet.demo.domain.AdminUser;<br /><br />public interface UserManager {<br />    //查询，不需要事务控制<br />    public boolean checkUser(String name, String password) throws SQLException;<br /><br />    //新增一个用户，需要事务控制，默认级别<br />    @Transaction<br />    public boolean addUser(AdminUser user) throws SQLException;<br /><br />}<br /><br />要把addUser改成其他事务隔离级别（比如oracle的serializable级别），稍微修改下：@Transaction(level=Connection.TRANSACTION_SERIALIZABLE)<br />public boolean addUser(AdminUser user) throws SQLException;<br /><br />不准备详细解释例子的业务流程，不过是登录和增加用户两个业务方法，看下就明白。阅读本文前最好已经读过开头提过的两篇文章。我相信代码是最好的解释：）<img src ="http://www.blogjava.net/killme2008/aggbug/98239.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-02-06 12:24 <a href="http://www.blogjava.net/killme2008/archive/2007/02/06/98239.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计自己的MVC框架</title><link>http://www.blogjava.net/killme2008/archive/2007/02/06/98227.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 06 Feb 2007 03:54:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/02/06/98227.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/98227.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/02/06/98227.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/98227.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/98227.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/02/06/98227.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/98227.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-02-06 11:54 <a href="http://www.blogjava.net/killme2008/archive/2007/02/06/98227.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>一个ServiceLocator模式的实现</title><link>http://www.blogjava.net/killme2008/archive/2007/02/06/98224.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 06 Feb 2007 03:49:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/02/06/98224.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/98224.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/02/06/98224.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/98224.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/98224.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/02/06/98224.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/98224.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-02-06 11:49 <a href="http://www.blogjava.net/killme2008/archive/2007/02/06/98224.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>缓存filter及资源池模式</title><link>http://www.blogjava.net/killme2008/archive/2007/02/06/98222.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 06 Feb 2007 03:47:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/02/06/98222.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/98222.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/02/06/98222.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/98222.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/98222.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 《J2EE设计模式》学习笔记&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/02/06/98222.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/98222.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-02-06 11:47 <a href="http://www.blogjava.net/killme2008/archive/2007/02/06/98222.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>设计模式之事务处理</title><link>http://www.blogjava.net/killme2008/archive/2007/02/06/98217.html</link><dc:creator>dennis</dc:creator><author>dennis</author><pubDate>Tue, 06 Feb 2007 03:32:00 GMT</pubDate><guid>http://www.blogjava.net/killme2008/archive/2007/02/06/98217.html</guid><wfw:comment>http://www.blogjava.net/killme2008/comments/98217.html</wfw:comment><comments>http://www.blogjava.net/killme2008/archive/2007/02/06/98217.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/killme2008/comments/commentRss/98217.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/killme2008/services/trackbacks/98217.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 事务处理是企业应用需要解决的最主要的问题之一。J2EE通过JTA提供了完整的事务管理能力，包括多个事务性资源的管理能力。但是大部分应用都是运行在单一的事务性资源之上（一个数据库），他们并不需要全局性的事务服务。本地事务服务已然足够(比如JDBC事务管理）。    本文并不讨论应该采用何种事务处理方式，主要目的是讨论如何更为优雅地设计事务服务。仅以JDBC事务处理为例。涉及到的DAO，Factory...&nbsp;&nbsp;<a href='http://www.blogjava.net/killme2008/archive/2007/02/06/98217.html'>阅读全文</a><img src ="http://www.blogjava.net/killme2008/aggbug/98217.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/killme2008/" target="_blank">dennis</a> 2007-02-06 11:32 <a href="http://www.blogjava.net/killme2008/archive/2007/02/06/98217.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>