<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0">
  <channel>
    <title>王杲杲</title>
    <description></description>
    <link>http://wang-zhenyu.javaeye.com</link>
    <language>UTF-8</language>
    <copyright>Copyright 2003-2008, JavaEye.com</copyright>
    <docs>http://blogs.law.harvard.edu/tech/rss</docs>
    <generator>JavaEye - 做最棒的软件开发交流社区</generator>
      <item>
        <title>民无信不立</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/51056" style="color:red;">http://wang-zhenyu.javaeye.com/blog/51056</a>&nbsp;
          发表时间: 2007年01月29日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p class="TextColor1" id="subjcns!CDE7AE7E326449DB!242" style="MARGIN-BOTTOM: 0px">《论语》中有一句话：自古皆有死，民无信不立。</p>
<div id="msgcns!CDE7AE7E326449DB!242">
<div>&ldquo;民无信不立&rdquo;是什么意思？于丹教授说是，人民对国家失去信仰，国家就会崩溃和涣散。</div>
<div>用的是&ldquo;信仰&rdquo;这个词儿。</div>
<div>曾经有一阵子，经常看文章&ldquo;信仰&rdquo;来&ldquo;信仰&rdquo;去地说事儿，我当时不知道&ldquo;信仰&rdquo;是个什么东东，现在好像也只知道个大概。</div>
<div>对于&ldquo;民无信&rdquo;这句话，我宁可理解为，人民对国家失去&ldquo;信任&rdquo;。</div>
<div>这不是一句废话么？</div>
<div>就好像《南都》一篇文章，说，贤臣劝说君王要&ldquo;亲君子远小人&rdquo;而没有随文附带一套君子小人鉴定器，就同样是废话，而且非常可气。</div>
<div>不是实际做事儿的人经常喜欢站在旁边说废话，好像还很有使命感，很难忍住不说。</div>
</div>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/51056#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 29 Jan 2007 14:24:45 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/51056</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/51056</guid>
      </item>
      <item>
        <title>Java的一个基础又简单的知识点：by value</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49955" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49955</a>&nbsp;
          发表时间: 2007年01月24日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">前几天，网上找了套java题目，给项目组成员做了一次考试，意图是让大家知道很多基础概念还不一定清楚，于是应该good good study，day day up。</font></p>
<p><font face="Arial">考试之后，有同事问起一个&ldquo;by value&rdquo;知识点相关的题目：</font></p>
<p><font face="Arial">Given the following code:</font></p>
<p><font face="Arial">public class Test{<br />
&nbsp;&nbsp;&nbsp; public static void main(String args[])<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; String str=new String(World);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char ch[]={'H','e','l','l','o'};<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; change(str,ch);</font></p>
<p><font face="Arial"><font face="Arial">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <font color="#0000ff">//System.out.println(str + &quot; and &quot; + ch);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;//这里，根据二楼、三楼兄弟指出的问题修改了题目。(多谢指正)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.print(str + &quot; and &quot;);<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; System.out.println(ch);</font></font><br />
</font><font face="Arial">&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; public static void change(String str, char ch[])<br />
&nbsp;&nbsp;&nbsp; {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; str=&quot;Changed&quot;; ch[0]='C';<br />
&nbsp;&nbsp;&nbsp; }<br />
}</font></p>
<p><font face="Arial">What is the result after execution?<br />
A. World and Hello<br />
B. World and Cello<br />
C. Changed and Hello<br />
D. Changed and Cello </font></p>
<p><font face="Arial">其他同事回信解释，涉及到&ldquo;final class&rdquo;和&ldquo;不变类&rdquo;两个概念。看来非常基础的概念也不是所有人都清楚，此次我把我回信的内容放在博客中，做个备份。可能会对非常非常初学的初学者有用。</font></p>
<p><font face="Arial">String类是final的没错，这只是说明它不能够被其他类extends。跟这里的题目是没有关系的。</font></p>
<p><font face="Arial">同时，String是不变类。没有任何一个语句可以在已经生成的String对象上做改变。比如&quot;CC&quot;是一个String对象，不可能有语句把&quot;CC&quot;的，比方说，第二个字符由&quot;C&quot;改成，比方说，&quot;A&quot;；&quot;CC&quot;自从它被初始化，就永远是&quot;CC&quot;，&quot;CA&quot;是另一个对象。是不是不变类，跟这里的题目也没关系。</font></p>
<p><font face="Arial">再比如另一段代码:</font></p>
<p><font face="Arial">public static void main(String[] args) {<br />
&nbsp;&nbsp;&nbsp; Person p = new Person(&quot;me&quot;);<br />
&nbsp;&nbsp;&nbsp; change(p);<br />
&nbsp;&nbsp;&nbsp; System.out.print(p.getName());//应该打印什么？<br />
}</font></p>
<p><font face="Arial">public static void change(Person p) {<br />
&nbsp;&nbsp;&nbsp; p = new Person(&quot;another one&quot;);<br />
&nbsp;&nbsp;&nbsp; p.setName(&quot;third one&quot;);<br />
}</font></p>
<p><font face="Arial">class Person {<br />
&nbsp;&nbsp;&nbsp; private String name;<br />
&nbsp;&nbsp;&nbsp; Person(String aName) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name = aName;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; void setName(String aName) {//可以看出，Person不是不变类。<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; name = aName;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; String getName() {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return name;<br />
&nbsp;&nbsp;&nbsp; }<br />
}</font></p>
<font face="Arial">
<p><br />
原来的题目中，change方法体中，str=&quot;Change&quot;；这句话是把str这个原本指向&quot;World&quot;对象的String类引用，指向了另一个对象&quot;Change&quot;。<br />
而main方法体中，调用change方法时候，JVM新做了一个str对象的拷贝、发往change方法、作为入参，就像int类型参数一样(这一点大家容易理解吧)；change函数体内将入参str的值改变(指向另一个对象)，不会影响到main方法中的str对象的值，即它的指向。</p>
<p>这里，by value的意思，不知道大家真正理解了没有。</p>
<p>str的value是对&quot;World&quot;这个对象的引用。</p>
</font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49955#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Wed, 24 Jan 2007 17:05:00 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49955</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49955</guid>
      </item>
      <item>
        <title>一个 阿伦雷奈 套装</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49110" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49110</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">&lt;我的美国舅舅&gt;<br />
一扫&lt;去年在马里昂巴&gt;给我留下的对 阿伦雷奈 的沉闷印象。<br />
冷峻、干练、犀利。<br />
&lt;我想要回家&gt;<br />
片中英语、法语混杂，只有法语字幕，我英语水平又只有这么凑合，于是没有看完。除了记得看过一点之外，没有更深的印象。<br />
&lt;几度风雨几度霜&gt;<br />
太好了。手法很新颖，隐隐地采用舞台效果，没有拉斯冯提尔&lt;狗镇&gt;处理得那么显眼，更多了点含混的趣味。<br />
剧情设计得很有味道（归功于编剧么？）。很多时候，编剧过于精巧、过于严丝合缝，反而失去很多力量，就好像&lt;撞车&gt;&lt;滑动门&gt;。这应该是符合某种美学规律的，不应该是简单的思维逆反。厚重的情感力量永远能打败纯粹的逻辑机巧。<br />
惊异于Sabine Azema的演技。<br />
&lt;生活像小说&gt;<br />
意思不大。<br />
&lt;生死恋&gt;<br />
太好了。<br />
让我对 阿伦雷奈 的御用演员四人组（Sabine Azema/ Fanny Ardant/ Pierre Arditi/ Andre Dussollier）印象深刻。后来整理碟子的时候发现，&lt;旅鼠&gt;中的年老男子原来是Andre Dussollier！<br />
执着（偏置），拥有无穷力量。自古即是。<br />
想起一首古诗&ldquo;上邪！我欲与君相知，长命无绝衰。山无棱，江水为竭，冬雷震震，夏雨雪，天地合，乃敢与君绝！ &rdquo;<br />
好多电影小说讲这个故事，永远感人。<br />
当然，这么说，会给&lt;生死恋&gt;带来误解。不是这样的，&lt;生死恋&gt;没有使用哪怕一点泛滥煽情的手法，大师不会跌这个份。<br />
同样是拍电影，水准差异上，真大。<br />
p.s.<br />
看了这么一套片子，有个感受。<br />
人一辈子时间也不多（一周又无声无息地过完了不是么），想看碟看书的时候，不要把时间浪费在烂书、烂碟上。<br />
当然，这么做，需要意志力和毅力。一堆片子，&lt;疯狂的石头&gt;之类永远先被看。当然Again，有些片子是为了看过之后做谈资的，另当别论，可以稍微原谅。呵呵。<br />
意志力、毅力！<br />
男人偶尔跟自己较点劲，应该不会错。</font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49110#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:25:13 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49110</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49110</guid>
      </item>
      <item>
        <title>成濑巳喜男-浮云</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49109" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49109</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">媳妇喜欢小津的调调<br />
周末看片的时候发现小津的片子散装套装都悉数看过<br />
找个差不多类型的吧<br />
李安的有么<br />
小房间已经很凌乱<br />
成濑巳喜男的套装恰好放在挺显眼的位置还没有开封<br />
我向来喜欢依循时间顺序<br />
于是打开&lt;浮云&gt;<br />
&nbsp;<br />
印象里是成濑的名作<br />
今天查了一下果然<br />
日本人把&lt;浮云&gt;排在百部佳作第二名足见其地位<br />
&nbsp;<br />
氛围和情绪营造很纯厚<br />
怪不得王家卫关锦鹏许鞍华都喜欢<br />
这几位也都是习惯于把大块大块情绪塞满整个放映时间尤其是王家卫<br />
&nbsp;<br />
&lt;浮云&gt;中人物树立丰满可成为一派典型<br />
今后可以说这个人真雪子那个人真富冈<br />
当然观者一定是不齿富冈叹惋雪子我也是<br />
浮云啊浮云片中谁是浮云呢<br />
光是雪子么两人都是吧<br />
&nbsp;<br />
付出总是叫人感动<br />
雪子<br />
&lt;我的美国舅舅&gt;中的话剧演员<br />
都算上<br />
&nbsp;<br />
很不错的片子啊<br />
还是要看大师<br />
前人封一些大师出来<br />
是为了节省我的时间么</font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49109#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:24:12 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49109</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49109</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Bad Smell &amp; Refactoring</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49107" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49107</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">Bad Smells &amp; Refactoring<br />
以前做的一个培训，当时备课时还是花了一些工夫。ppt贴不上来，把备课稿贴在这，备份一个吧。<br />
&nbsp;<br />
Bad Smells &amp; Refactoring<br />
1 题记<br />
Any fool can write code that a computer can understand. Good programmers write code that humans can understand.&mdash;&mdash;Martin Fowler<br />
（任何一个傻瓜都能写出计算机可以理解的代码。唯有写出人类容易理解的代码，才是优秀的程序员。）<br />
2 Bad Smells<br />
2.1 Duplicated Code重复的代码<br />
（重复代码，不需要定义，大家都知道是什么东东。）<br />
1． &ldquo;重复的代码&rdquo;有什么不好？（比方说，从可维护性的角度看，很多地方的代码看似一样，又有可能有细微差别，对读代码的人容易产生困扰，于是可以定罪，可读性不好；同样的修改可能需要修改多次，而且容易遗漏，可修改性不好。）（但是，重复代码也有好处啊，代码行数多，千行代码故障率会少，对我们的考核比较有利&hellip;&hellip;开玩笑的是么？）<br />
2． 代码重复到什么程度，Smell才算Bad？（if (filename == null || filename.trim().equals(&quot;&quot;))这句话可作为例子，我们认为这句话就算是重复代码了，比如哪天filename.trim().equals(&quot;&quot;)这个判断我觉得不好，想要换成filename.trim().length() == 0，那么岂不是霰弹式修改？使用绝技&ldquo;Ctrl-C/ Ctrl-V&rdquo;、同时还有用&ldquo;Ctrl-F&rdquo;，因为大家没有住在一起，要搜索一下才联系得到&hellip;&hellip;）<br />
3． 三种情况的重复代码：<br />
a) 同一个class中的两个method含有相同表达式。（Extract Method）<br />
b) 两个互为兄弟的subclass内含有相同表达式。（Extract Method、Pull up Method、Form Template Method）<br />
c) 两个毫不相关的class内含有相同表达式。（ Extract Method、 Extract Class）<br />
2.2 Long Method过长函数<br />
2.2.1 &ldquo;过长函数&rdquo;有什么不好？<br />
1． 可读性：使用短函数，高层函数看起来像系列注释、低层函数不超过（比方说）10行，逻辑一目了然，可读性更优。<br />
2． 可重用性：（长函数可能包含逻辑A/B/C，想单独重用A逻辑，不可能。一个类比的例子，发动机的重用机会肯定比车大。大家知道深圳BYD使用的是三菱发动机，标致307/206 1.6系列使用的发动机跟富康、爱丽舍16V系列是相同的。发动机上面的螺丝重用机会更大。很多不同种类发动机上使用的螺丝很可能是同一个厂家生产的相同螺丝。）<br />
3． 可插入性：使用短函数，利用Override等操作，替换处理逻辑会更加容易。比如，更容易应用模板方法模式Template Method，参见Form Template Method章节。<br />
2.2.2&nbsp; &ldquo;短函数&rdquo;难道没有缺点？<br />
1． 调用开销？（现代OO语言几乎已经完全免除了进程内的&ldquo;函数调用动作的额外开销&rdquo;。）<br />
2． 看代码的时候，跳来跳去，很心烦？（高层函数看起来像系列注释，而且函数名字起得好，单纯看代码，比如接手模块的时候，低层的函数甚至可以不看。）<br />
2.2.3 函数到了多长，Smell才算Bad？（写多长的函数才比较合适？）<br />
1． 李维说：5行。（李维大家认识么？台湾IT界著名散文家，与侯捷齐名。不得不承认，此处我断章取义了，他说&ldquo;5行&rdquo;，是有一定语境的，他是想说&ldquo;很短&rdquo;的意思，建议大家不要追究他说的是5还是6。）<br />
2． Martin Fowler说：长度不是问题，关键在于函数名称和函数本体之间的语义距离。（Martin Fowler大家认识么？《重构》《UML精粹》《分析模式》《企业应用架构模式》等经典著作的作者。后面，Martin还是，如果提炼动作可以强化代码的清晰度，那就去做，就算函数名称比提炼出来的代码还长也无所谓。什么叫做&ldquo;函数名称与函数本体之间的语义距离&rdquo;？函数名称要能概括函数体的动作，我引用的这句话没有能表达Martin的所有意思。）<br />
3． 王振宇说：应该很短、可以较长，只要函数是在做一件从语义上无法再次拆解的事。（王振宇大家认识么？注意到没有，我们认为这句话是对Martin上一句话的补充，在函数体的组织方式上做了要求。简单说就是，一个函数做一件事儿。Extract Method中的那个例子。）<br />
2.3 Large Class（过大类）<br />
（一个例子）<br />
1． &ldquo;过大类&rdquo;有什么不好？（难维护、容易出现重复代码。）<br />
2． &ldquo;过大类&rdquo;的常见情况：<br />
a) 本应该是针对不同类的操作放到一个类中。（比如，某些类本应拆出一些小的零件类，该类与零件类之间可能是关联、依赖关系，但没有这么做，而是所有代码放在一个类中。）<br />
b) 大量静态方法放在&ldquo;*Comm&rdquo;类中。<br />
i. 现象：大量静态方法放在&ldquo;Comm&rdquo;类中。很像C的函数库。（这个现象常见么？好不好？）<br />
ii. 评述：这是一种使用面向对象语言编写面向过程代码的尝试。我个人觉得这类尝试是一种倒退，拒绝面向对象所带来的所有特性。没有很好地封装，程序的结构化不好；使用方与之的依赖是静态的；没有可插入性。<br />
iii. 措施：解决这个问题的做法是，按照操作实施在哪个对象身上来把操作规划到对象所在的类里面；如果保持静态方法不变，也不要所有方法放到一个类中，最好按照语义来划分到合适的类。JDK类库提供了那么多方法，很少出现静态函数库的现象。当然，也不是说不存在，比如Math、ArrayList等类，不过至少他们在语义上分得很清晰。一个例子，比如，String的substring方法，很可能被一些程序员设计成public static，因为他们可能觉得无法把这个方法归属到哪个类中，于是放到&ldquo;Comm&rdquo;类中。（大家体会一下？是不是这么个事儿。）<br />
iv. 疑问：那不是想调用某个方法的时候就要new一个实例（性能问题！）？首先，这又是面向过程的思维方式，想的是过程、调用，而不是对象、依赖、关联。其次，轻量级的对象，创建、回收成本很低。我曾经对一些不同算法、策略从性能角度做过相应的比较试验，通常，执行次数在10w-100w以上量级时，才有差别。我使用面向对象的做法，可以明显地获得更优的可维护性（可读、可扩展、可改、可插入、可重用），而且面向对象本身不会造成什么性能问题。当然，具体情况要具体分析，如有明显的性能隐患，最好能够做一个简单的试验，用数据来说话。做个类比，说某些政客在很多场合的潜台词中认为，民主、自由会破坏安定的大好局面，显然不能够让人信服；同样，说面向对象增加了对象的创建、销毁成本，会影响性能，影响软件系统的稳定局面，也是不能够让人信服的。于是在编程时尽可能地使用静态方法，这种做法，不可取。<br />
3． 类长到多大才算&ldquo;Large&rdquo;？类，应该较小、可以较大，只要该类从语义上无法再次拆解。（&ldquo;发动机&rdquo;类，可以包含对&ldquo;螺丝&rdquo;类的引用（关联），但不要把&ldquo;螺丝&rdquo;类的操作也放到&ldquo;发动机&rdquo;类中来实现。）<br />
2.4 Long Parameter List（过长参数列）<br />
1． &ldquo;过长参数列&rdquo;有什么不好？（难读、难用、难记，还有一点，无法获得对象所带来的优势。比如，参数之间的约束关系没有得到很好地封装。例如，startTime/endTime，他俩作为参数来讲，可能不算长，这里仅做示例来说事儿。这对表示时间范围的参数可能多处使用，在没有包装成对象的时候，如果要保证&ldquo;startTime &lt; endTime&rdquo;这个约束，就需要所有用到这对参数的地方都做判断；包装成对象，情况就好多了，比如叫做TimeRange，在类的构造函数中可以做这个判断。显然，使用对象，把变化封装得好一些。）<br />
2． 想一下，JAVA类库的函数，比起C类库的函数，传递的参数是不是大都短很多？（应该是。这体现了面向对象的优势。）<br />
3． &ldquo;参数太多&rdquo;这个Smell如何去除？<br />
a) Introduce Parameter Object，无非是把多个参数封装成一个对象。<br />
2.5 Divergent Change（发散式变化）<br />
1． 什么是&ldquo;发散式变化&rdquo;？<br />
a) &ldquo;某一个类受到多种变化的影响&rdquo;，A/B/C/D&hellip;&hellip;多种功能变化的时候它都需要修改。<br />
2． 为什么会造成&ldquo;发散式变化&rdquo;？哪儿没弄好？<br />
a) 大致是由于这个类担负了多项任务，太操心了，不该他做的事儿也来做，越俎代庖。很可能需要再拆分几个类出来，把变化封装得更细。<br />
3． 历史教训（反面教材）（以前我写配置MAF端代码的时候，写过一个P_Unit类，他处理所有BSC单元的逻辑，但各种单板的逻辑是不一样的，于是DTB改逻辑的时候要修改P_Unit、ABPM改的时候要修改P_Unit、IPCF、UPCF、GCM&hellip;&hellip;所有具有特殊逻辑的单板修改功能的时候，他都要修改，甚至HDLC/UID等逻辑修改的时候P_Unit都要改。显然该类管得太多了。后来，我看了一本书，翻然悔悟，痛下把代码决心做了重构。其实早在03年，徐峰（据说徐峰要离开公司，这么牛的人离开了对我们整个OMC损失很大，我在这里提一下他的名字，简陋地送别一下。）做配置CAF的时候建议我针对每种有特殊逻辑的板子弄一个类，我完全不以为然。显然，当时没有理解&ldquo;封装变化&rdquo;这四个字。）<br />
2.6 Shotgun Surgery（霰弹式修改）<br />
1． 什么是&ldquo;霰弹式修改&rdquo;？<br />
a) &ldquo;一个变化引发多个类的修改&rdquo;，完成某个需求的时候，A/B/C/D&hellip;&hellip;多个类都需要修改。<br />
2． 为什么会造成&ldquo;霰弹式修改&rdquo;？哪儿没弄好？<br />
a) 大致是多个类之间的耦合太严重。很可能是类没有规划好，没有把变化封装得足够令人满意。<br />
3． 一个插曲：记得此前讨论这个Bad Smell的时候，严钧认为，去掉这个Bad Smell不好强求，而且举出Abstract Factory模式作为例证。也有道理。我在这一点上是这么认为的：我们要清楚的认识到我们努力的方向，Abstract Factory模式同样不完美，它没有满足Open-Close原则。我们可以在某些条件（包括技术条件）受限的时候写出不完美的代码，但一定要知道它是不完美的。<br />
a) Factory Method模式（工厂方法）代替Abstract Factory来说事儿。<br />
&nbsp;<br />
每增加一种Produce的实现类，就要同时增加一个对应该类的Creator类。当时严钧可能说的是Abstract Factory模式，我用Factory Method模式来说事儿，因为他简单些，但同样可以说明问题。<br />
b) Open-Close原则<br />
软件实体应该对扩展开放，对修改关闭。Open-Close原则是一个愿景性质的原则，如果系统能够达到Open-Close原则描述的情形就比较理想了，对扩展开放、对修改关闭，即，不修改原有代码即可完成对系统的扩展。系统可以获得最大可能的稳定性，加功能的时候旧有代码不修改，当然不会带入BUG。<br />
? 玉帝招安美猴王的故事<br />
齐天大圣美猴王，想当初可是功夫了得，从东海龙王那儿拿了根棍儿，大闹天宫&hellip;&hellip;叫嚣得不行（后来怎么不灵了，一根灯草、一根头绳、一条看大门的狮子狗都整不过），喊出来一些革命口号：&ldquo;皇帝轮流做，明年到我家&rdquo;，&ldquo;只教他搬出去，将天宫让与我！&rdquo;。有一些农民起义领袖的风范。<br />
太白金星给玉皇大帝打了个报告出主意：&ldquo;把他宣来上界&hellip;&hellip;与他籍名在箓&hellip;&hellip;一则不动众劳师，二则收仙有道也&rdquo;。<br />
玉皇大帝遵循Open-Close原则招安了美猴王。不动众劳师，不破坏天规，是关闭对已有系统的修改，不修改，是Closed。收仙有道，是对已有系统的扩展，可扩展，是Open。<br />
&nbsp;<br />
同时应用了依赖倒换原则，合成/聚合复用原则，以后有机会给大家讲讲面向对象的设计原则。<br />
4． 讲回霰弹式修改这个smell，很多程序在接手时，前辈一再嘱咐，改什么功能的时候，一定要注意，什么什么&hellip;&hellip;一堆地方必须同时修改，要细心不要漏了&hellip;&hellip;这很可能是设计水平的问题给维护造成的难度。其实如果程序设计得好，此后的工作将愉快很多。（插播广告）我记得，刚看到斯诺克比赛在电视上转播的时候（那时候还小，初中吧，还没见过真的斯诺克台球桌），很不屑，觉得他们大部分时候在打一些比较近距离的球，最多半张台子距离吧，我甚至盲目自信，感觉那些球我都能打进，电视上的人有什么了不起。其实大家都知道，母球走位是难度更大、更重要的工作（要经过全盘性思考的），走位走好了，下一杆就好打；就好比做软件，程序结构设计得好，维护就更容易。<br />
2.7 Data Clumps（数据泥团）<br />
1． 什么是&ldquo;数据泥团&rdquo;？<br />
a) 某些数据项经常黏在一起行动，称之为&ldquo;数据泥团&rdquo;。时间长了就应该考虑是不是该把他们封装到一个对象中，来封装这个泥团所可能具有的逻辑。（比如一堆表示定位信息的字段，system、subsystem、unit、rack、shelf、slot&hellip;&hellip;总是一起出现。）（这个Bad Smell在在很多时候与Long Parameter List，是一样的，但Data Clumps的涵盖范围比Long Parameter List要大一些，比如，某些类的Field，可能没有当作参数来传递，但是总是黏在一起，也可能出现数据之间的逻辑，于是也需要绑成一个对象，来做封装。）<br />
2． 如何判断是否属于&ldquo;数据泥团&rdquo;？<br />
a) 删掉这些数据项中的其中之一项，其他数据有没有因此失去意义？（比如startTime/ endTime，就是成对表示时间范围的，去掉其中一个，另一个失去意义。）<br />
2.8 Switch Statements（Switch惊悚现身）<br />
（惊悚现身，很像香港翻译好莱坞电影片名的风格是么？）<br />
1． Switch语句有什么不好？<br />
a) 容易形成&ldquo;长函数&rdquo;（比较容易理解）<br />
b) 容易形成&ldquo;霰弹式修改&rdquo;<br />
2． 如何替换掉Switch语句？<br />
a) 多态（使用Pet的例子的第三个版本来说明）<br />
3． 是不是使用多态可以去掉所有Switch语句？<br />
a) 不是。比如，根据消息号，分发把消息分发到相应的处理函数（处理类）来处理。（原因是某些情况下，调用端无法动态创建确切（子类的）实例，于是依然需要分发过程。即，需要Switch语句分发、或者&ldquo;配置文件+反射&rdquo;的方式分发。）<br />
4． 对Switch语句有什么要求？<br />
a) Switch语句可以存在，但每个case的处理语句不应超过2-3行。<br />
2.9 Comments（过多的注释）<br />
（首先，注释本身没有错，很多时候注释是必须存在的。但，注释过多，就是坏味道了。）<br />
1． Why？为什么？<br />
a) 过多的注释，是降低代码可读性的帮凶。（如果，代码只有通过大量注释才能被理解，那么说明代码的可读性不好。事实上，很多文章也就此有些说法：代码要写得&ldquo;自解释能力强&rdquo;、自己解释自己；代码就是文档。这就要求，类、方法的编写要清爽，类名、方法名、变量名要起得好。）<br />
2． How？如何写好注释？（Why？How？想起那个关于两个渔夫和一个美人鱼的荤笑话，由于有未成年人士在场，我不便当众详细讲。）<br />
a) 写&ldquo;why&rdquo;。（注释应该写代码的编写思路，特别是某些地方没有按常理出牌，要写注释来说明。比如，对数组做for循环遍历，边界一般是数组的length，如果某一次出于某种特殊考虑，没这么做，就需要注释说明。）<br />
b) 不写&ldquo;what&rdquo;。（注释不要写代码是干什么的，&ldquo;what&rdquo;这样的信息应该尽量包含在类名、方法名、变量名中。）<br />
c) 不写充数注释。（不要为了写注释而写注释，不要往猪肉里注水，虽然没什么大碍，但终归是没品味的做法。比如，&ldquo;String a = null;//创建一个String实例。&rdquo;看到这样的注释，我胃口都不舒服。虽然部门有注释比例的要求，但像我们这样的高级程序员、高级工程师，还是不要充数用的注释。）<br />
3 Refactoring<br />
3.1 Extract Method<br />
void printOwing() {<br />
&nbsp; printBanner();<br />
&nbsp; //print details<br />
&nbsp; System.out.println (&quot;name:&quot; + _name);<br />
&nbsp; System.out.println (&quot;amount&quot; + getOutstanding());<br />
}<br />
重构为：<br />
void printOwing() {<br />
&nbsp; printBanner();<br />
&nbsp; printDetails(getOutstanding());<br />
}<br />
void printDetails (double outstanding) {<br />
&nbsp; System.out.println (&quot;name:&quot; + _name);<br />
&nbsp; System.out.println (&quot;amount&quot; + outstanding);<br />
}<br />
（前面说了，函数应该短。重复一下带来的好处：可读性好，高层函数像注释、低层函数行数少；可重用性好，比如上例中的printDetails，可能别处也能用，重构前是无法被重用的；可插入性好，子类可能写一个新的printDetails，使用不同格式打印。）<br />
3.1.1 抽取函数时候，参数、临时变量如何处理<br />
1． Replace Temp With Query 去掉临时局部变量，代之以查询类的方法，拆开的小函数需要此临时变量的时候，就调用这个查询方法。<br />
2． Introduce Parameter Object 让长参数列变得简洁。<br />
3． Replace Method with Method Object 去掉多个参数、局部变量。为待重构的大函数创建一个对象，这样，所有方法内的临时变量就变成对象的field，于是大函数拆开的所有小函数就共享这些field，不必再使用参数传递。<br />
3.1.2 起名字很重要！名字应该：（此处的名字包括函数、类等）<br />
1． 清晰、恰当。表达的信息涵盖函数的所作所为。<br />
a) 当一个函数名字为了涵盖函数所为&ldquo;必须&rdquo;起成&ldquo;do1stThingAndDo2ndThing&rdquo;的时候，就有必要实施Extract Method来抽取函数了。<br />
b) 一个OMC代码中的例子，某函数叫做checkParameter，但函数体中除了检查参数之外，还&ldquo;顺便&rdquo;为几个类属性赋值，虽然此函数很短、很超值，但我们认为他的命名是不恰当的，甚至他的函数设计也是不恰当的，一个函数要干单纯的一件事儿，函数内部从语义上无法再次分解。<br />
2． 尽量简短、可以较长。但应该首先满足上一条要求。<br />
a) compareToIgnoreCase（String类的方法）、getDisplayLanguage（Locale类的方法）、getTotalFrequentRenterPoints（《重构》书中的示例代码），这些函数名长不长？（重要的是把信息表述清楚，名字长一点没关系。）<br />
3.2 Replace Temp with Query<br />
double basePrice = _quantity * _itemPrice;<br />
if (basePrice &gt; 1000)<br />
&nbsp; return basePrice * 0.95;<br />
else<br />
&nbsp; return basePrice * 0.98;<br />
重构为：<br />
if (basePrice() &gt; 1000)<br />
&nbsp;&nbsp;&nbsp; return basePrice() * 0.95;<br />
&nbsp; else<br />
&nbsp;&nbsp;&nbsp; return basePrice() * 0.98;<br />
&hellip;<br />
double basePrice() {<br />
&nbsp; return _quantity * _itemPrice;<br />
}<br />
（例子很容易理解，basePrice是临时变量，临时变量的问题在于：它们是暂时的，而且只能在所属函数内使用。由于临时变量只有在所属函数内才可见，所以它们会驱使你写出更长的函数，因为只有这样你才能访问到想要访问的临时变量。如果把临时变量替换为一个查询式（query method），那么同一个class中的所有函数都将可以获得这份信息。为拆解大函数提供了方便。）<br />
3.2.1 一个借助Replace Temp with Query来提炼函数的例子<br />
double getPrice() {<br />
&nbsp;&nbsp;&nbsp; int basePrice = _quantity * _itemPrice;<br />
&nbsp;&nbsp;&nbsp; double discountFactor;<br />
&nbsp;&nbsp;&nbsp; If (basePrice &gt;1000) discountFactor = 0.95;<br />
&nbsp;&nbsp;&nbsp; else basePrice = 0.98;<br />
&nbsp;&nbsp;&nbsp; return basePrice * discountFactor;<br />
}<br />
重构为：<br />
double getPrice() { <br />
&nbsp;&nbsp;&nbsp; return basePrice() * discountFactor();<br />
}<br />
private int basePrice() {<br />
&nbsp;&nbsp;&nbsp; return _quantity * _itemPrice;<br />
}<br />
Private double discountFactor() {<br />
&nbsp;&nbsp;&nbsp; If (basePrice() &gt;1000) return 0.95;<br />
&nbsp;&nbsp;&nbsp; else return 0.98;<br />
}<br />
（重构前，在getPrice方法中，先计算基础价格、再计算折扣因子、再计算最终价格，做了语义上可以再次拆解的三件事儿，不符合&ldquo;函数只做一件事儿&rdquo;的要求，于是使用Extract Method方法来重构。借助Replace Temp with Query重构方法，将临时变量basePrice、discountFactor用相应的查询函数来替代。<br />
需要指出的是，此次重构，查询函数basePrice被调用了两次，损失的一点点性能可以忽略，我们认为这样做是值得的。）<br />
3.3 Split Temporary Variable<br />
double temp = 2 * (_height + _width);<br />
System.out.println (temp);<br />
temp = _height * _width;<br />
System.out.println (temp);<br />
重构为：<br />
final double perimeter = 2 * (_height + _width);<br />
System.out.println (perimeter);<br />
final double area = _height * _width;<br />
System.out.println (area);<br />
（如果临时变量被赋值超过一次就意味它们在函数中承担了一个以上的责任（循环变量等用途除外）。<br />
例子中，临时变量temp开始被用来记录矩形周长，后来被用来记录矩形面积。应该拆解为多个临时变量，否则：<br />
1． 影响代码可读性。（多用途临时变量通常无法获得合适的命名）<br />
2． 增加代码出错机会。（程序某处，可能都记不清这个临时变量现在是记录什么数值的）<br />
实际操作中，推荐使用final来限定临时变量被赋值次数。）<br />
3.4 Remove Assignments to Parameters<br />
int discount (int inputVal, int quantity, int yearToDate) {<br />
&nbsp;if (inputVal &gt; 50) inputVal -= 2;<br />
重构为：<br />
int discount (int inputVal, int quantity, int yearToDate) {<br />
&nbsp;int result = inputVal;<br />
&nbsp;if (inputVal &gt; 50) result -= 2;<br />
1． 不要对参数赋值<br />
void nextDate(Date arg) {<br />
&nbsp;&nbsp;&nbsp; arg.setDate(arg.getDate() + 1);<br />
}<br />
void nextDate(Date arg) {<br />
&nbsp;&nbsp;&nbsp; arg = new Date(arg.getYear(), arg.getMonth(), arg.getDate() + 1);<br />
}<br />
上面两个函数的写法，哪个是对参数赋值了的？哪个会起到应有的作用？<br />
2． Java是pass by value（传值）的<br />
a) 传进函数体中的参数，是调用语句那个传入参数在内存中的一份拷贝<br />
b) 函数体内对参数的再赋值不会影响调用方的参数原始值（比如，修改int等基本类型参数的数值、修改Object等对象引用的指向）<br />
c) Java中，对参数的再次赋值是一种纯粹降低程序清晰程度的做法<br />
3.5 Replace Method with Method Object<br />
class Order...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; double price() {<br />
&nbsp;double primaryBasePrice;<br />
&nbsp;double secondaryBasePrice;<br />
&nbsp;double tertiaryBasePrice;<br />
&nbsp;// long computation;<br />
&nbsp;...<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&hellip;<br />
重构为：<br />
&nbsp;<br />
（一个大的函数，提炼出一个专门实现这个函数功能的类。<br />
比如getMoney方法可能就是提炼出一个MoneyGetter类。此处是price方法提炼出PriceCalculator类。<br />
这样做的理由是，price可能是个很大的函数，我们为了获得短函数的优势（前面说过的，可重用、可读、可插入等），想利用Extract Method抽取出多个短函数，但每个短函数可能都需要primaryBasePrice、secondaryBasePrice、tertiaryBasePrice等几个临时变量，把它们都作为参数传递显然太笨了。而把这个大函数提炼成类，这些临时变量就变成了类的Field，在类中是共享的，这样，抽取出来的小函数之间就可以不需要传递参数，就很容易实现Extract Method这个重构过程。）<br />
3.5.1 如此这般之后，类是不是太多了？<br />
面向对象的套路，玩的就是类。函数不嫌多，为什么嫌类多？多个风马牛不相及的函数杂居在一个类中（能够容忍么？），为什么不多弄几个类把它们各自封装？类，对应了现实世界的有机无机物种，把物种分得足够细致，世界才得到了完美地描述。<br />
3.6 Replace Array with Object<br />
String[] person = new String[3];<br />
person[0] = &ldquo;Robert De Niro&quot;;<br />
person[1] = &ldquo;60&quot;;<br />
person[2] = &ldquo;Actor&rdquo;;<br />
重构为：<br />
Person robert = new Person();<br />
robert.setName(&quot; Robert De Niro&quot;);<br />
robert.setAge(&ldquo;60&quot;);<br />
robert.setProfession(&ldquo;Actor&rdquo;);<br />
1． 数组应该容纳一组相似的对象，用户很难记住&ldquo;数组第一个元素是人名、第二个元素是年龄&rdquo;这样的约定。<br />
a) 用注释来保证这种约定么？<br />
b) 使用数组是出于效率考虑么？（抬杠？）<br />
2． 同理，能够恰当地利用既有数据结构把接口约束得紧一些（更贴切、更严丝合缝），对大家都有好处。<br />
a) 比如，能够确定是一组Person类实例，就要用Person[]来装，而不用Set、Map这样的&ldquo;广口&rdquo;容器。（拒绝&ldquo;私下、口头约定，注释&rdquo;等靠不住的协议方式所带来的弊端。）<br />
3.7 Encapsulate Field<br />
public String _name;<br />
重构为：<br />
private String _name;<br />
public String getName() {<br />
&nbsp;&nbsp;&nbsp; return _name;<br />
}<br />
public void setName(String arg) {<br />
&nbsp;&nbsp;&nbsp; _name = arg;<br />
}<br />
强调封装：<br />
一般来讲，任何时候都不要将类field声明为public（常量除外）。数据和使用数据的行为被集中在一起，一旦情况发生变化，代码的修改比较容易，因为需要修改的代码都集中在同一块地方，而不是星罗棋布地散落在整个程序中。<br />
3.8 Replace Magic Number with Symbolic Constant<br />
double potentialEnergy(double mass, double height) {<br />
&nbsp;return mass * 9.81 * height;<br />
}<br />
重构为：<br />
double potentialEnergy(double mass, double height) {<br />
&nbsp;return mass * GRAVITATIONAL_CONSTANT * height;<br />
}<br />
static final double GRAVITATIONAL_CONSTANT = 9.81;<br />
宏值定义代替散落在代码中的&ldquo;魔术数&rdquo;，没什么好说的。<br />
3.9 Encapsulate Collection<br />
&nbsp;<br />
重构为：<br />
&nbsp;<br />
依然是强调封装：<br />
1． 类内高内聚：数据和对数据的操作紧密结合在一起，对数据的实施操作比较容易。（比如，餐厅管理系统中的某个类，dishes（Vector类型）作为类的field，装载点菜时被点中的菜目，如果想统计一下哪些菜受欢迎，对于按Encapsulate Collection设计的类就比较容易操作，add方法中做一些手脚即可（分类累加）。）<br />
2． 类之间松耦合：内部数据结构不要暴露的外界，外界也不需要关心。（这样，即便你把内部数据由array换成Vector，外部都不需要知道。）<br />
3.10 Replace Type Code with Class<br />
&nbsp;重构为： <br />
3.10.1 Why？Type Code有什么不好？<br />
1． Type Code会降低可读性。<br />
a) 在定义的地方可能看不出来（定义时使用宏值，可读性挺好），但在使用的地方就会显现问题。上例中，比如有个方法getCharacter获得血型对应的性格描述，参数是血型，使用Type Code时，参数类型为int，重构后，参数类型为BloodGroup，显然后者的可读性好。<br />
2． 使用Type Code失去了使用对象所拥有的独立扩展的机会。<br />
a) 像这个例子，Type Code很容易有它自己的行为，比如根据血型得到性格描述、得到ABO溶血症可能性、判断血型之间的输血匹配可能&hellip;&hellip;于是将其抽取成类是比较好的做法。（还是封装！）<br />
3.10.2 插科打诨，Meilir Page-Jones讲的故事<br />
（故事是讲面向对象的，面向对象的主要特征有哪些？封装、继承、多态）<br />
Meilir Page-Jones在《UML面向对象设计基础》（个人认为此书堪称经典）一书中编了一个故事：<br />
软件界在&ldquo;面向对象&rdquo;的定义上，一度很难达成一致。我开始步入面向对象领域时，决定澄清一下&ldquo;面向对象&rdquo;的定义。<br />
我把数十位面向对象的老前辈关在一个没有食物和水的房间里。我告诉他们只有当他们的定义达成一致的意见，并且可以在软件世界发布时才允许他们出去。在一小时的喧哗过后，房内一片安静，老前辈们背靠背谁也不理谁了，陷入了僵局。此时，蹦出来一位组织者，让每个人都列出他们认为在面向对象世界中不可缺少的特性，大家同意。一通罗列，每个人都列出了三个五个、十个八个。<br />
此时，刚才蹦出来那位组织者又蹦出来开始讲话，说，现在我们大致有两种做法：一种是建立一个长列表，该列表是每个人列表的并集；另一种是建立一个短列表，该列表是每个人列表的交集。大家选择了后者，产生了一个短列表，该列表中的特性在每个人列表中都有。这个列表确实很短，短到只有一个词，&ldquo;封装&rdquo;。<br />
一堆废话告诉大家一个道理，封装，是面向对象最为重要的特性，封装好了，才能做到所谓的高内聚、松耦合。获得面向对象思想许诺的种种优势。<br />
3.11 Replace Type Code with Subclass<br />
（跟前面宠物店的例子是不是很像？）<br />
&nbsp;重构为： <br />
3.12 Replace Type Code with State/Strategy<br />
&nbsp;重构为： <br />
这个就厉害了！清晰地展示了&ldquo;合成/聚合复用原则&rdquo;。<br />
上面例子，将Engineer和Salesman弄成并列的子类，是存在问题的。（什么问题？）<br />
1． Salesman明确地从Employee继承，那么就无法再从Male、Newcomer等类继承来获得他们的特性。<br />
2． Salesman的实例被new出来之后，他可能转岗做研发，想变成Engineer，无法实现。<br />
3.12.1 什么是合成/聚合复用原则<br />
1． 要尽量使用合成/聚合，尽量不要使用继承。<br />
2． 从复用角度来说：&ldquo;合成/聚合复用&rdquo;比&ldquo;继承&rdquo;复用灵活。前者是动态复用（因而具有可插入性）、后者是静态复用（编译时就固定了复用关系），而且后者的复用有&ldquo;不支持多重继承&rdquo;的限制。<br />
3.13 Decompose Conditional<br />
if (date.before (SUMMER_START) || date.after(SUMMER_END))<br />
&nbsp;&nbsp;&nbsp; charge = quantity * _winterRate + _winterServiceCharge;<br />
else charge = quantity * _summerRate;<br />
重构为：<br />
if (notSummer(date))<br />
&nbsp;&nbsp;&nbsp; charge = winterCharge(quantity);<br />
else charge = summerCharge (quantity);<br />
Extract Method在条件判断语句段中的应用。<br />
3.14 Consolidate Conditional Expression<br />
double disabilityAmount() {<br />
&nbsp;if (_seniority &lt; 2) return 0;<br />
&nbsp;if (_monthsDisabled &gt; 12) return 0;<br />
&nbsp;if (_isPartTime) return 0;<br />
&nbsp;// compute the disability amount<br />
重构为：<br />
double disabilityAmount() {<br />
&nbsp;if (isNotEligableForDisability()) return 0;<br />
&nbsp;// compute the disability amount<br />
这条比较雕虫小技，可视具体情况参考实施。<br />
3.15 Consolidate Duplicate Conditional Fragments<br />
if (isSpecialDeal()) {<br />
&nbsp; total = price * 0.95;<br />
&nbsp; send();<br />
}<br />
else {<br />
&nbsp; total = price * 0.98;<br />
&nbsp; send();<br />
}<br />
重构为：<br />
if (isSpecialDeal()) {<br />
&nbsp; total = price * 0.95;<br />
}<br />
else {<br />
&nbsp; total = price * 0.98;<br />
}<br />
send();<br />
虽然这条也比较雕虫小技，但前面这样的代码确实也有人写得出来。<br />
3.16 Remove Control Flag<br />
set done to false<br />
while not done<br />
&nbsp;&nbsp;&nbsp; if (condition)<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; do something<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; set done to true<br />
&nbsp;&nbsp;&nbsp; next step of loop<br />
Control Flag为什么不好？<br />
影响可读性，程序看起来比较绕。<br />
3.16.1 一个例子<br />
void checkSecurity(String[] people) {<br />
&nbsp; String found = &quot;&quot;;<br />
&nbsp; for (int i = 0; i &lt; people.length; i++) {<br />
&nbsp;&nbsp;&nbsp; if (found.equals(&quot;&quot;)) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (people[i].equals (&quot;Don&quot;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendAlert();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; found = &quot;Don&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (people[i].equals (&quot;John&quot;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendAlert();&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; found = &quot;John&quot;;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
&nbsp; someLaterCode(found);<br />
}<br />
无论找到Don还是John都退出循环做其他事儿。注意：这里使用了标志found。<br />
重构为：<br />
void checkSecurity(String[] people) {<br />
&nbsp; String found = foundMiscreant(people);<br />
&nbsp; someLaterCode(found);<br />
}<br />
String foundMiscreant(String[] people){<br />
&nbsp; for (int i = 0; i &lt; people.length; i++) {<br />
&nbsp;&nbsp;&nbsp; if (people[i].equals (&quot;Don&quot;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendAlert();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &quot;Don&quot;;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; if (people[i].equals (&quot;John&quot;)){<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; sendAlert();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return &quot;John&quot;;<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp; }<br />
&nbsp; return &quot;&quot;;<br />
}<br />
重构之后，去掉了标志，增加了函数的出口，同时增加了程序的可读性。<br />
3.17 Replace Nested Conditional with Guard Clauses<br />
（卫语句：某些条件判断为真时，立即从函数返回。这样的判断就应该首先、单独进行，把这种单独检查称之为&ldquo;卫语句&rdquo;。Guard Clauses。是Kent Beck给起的名字，Kent Beck是TDD、XP的第一倡导者。）<br />
double getPayAmount() {<br />
&nbsp; double result;<br />
&nbsp; if (_isDead) result = deadAmount();&nbsp; <br />
&nbsp; else {<br />
&nbsp;&nbsp;&nbsp; if (_isSeparated) result = separatedAmount();<br />
&nbsp;&nbsp;&nbsp; else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (_isRetired) result = retiredAmount();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else result = normalPayAmount();<br />
&nbsp;&nbsp;&nbsp; };<br />
&nbsp; }<br />
&nbsp; return result;<br />
};<br />
重构为：<br />
double getPayAmount() {<br />
&nbsp; if (_isDead) return deadAmount();<br />
&nbsp; if (_isSeparated) return separatedAmount();<br />
&nbsp; if (_isRetired) return retiredAmount();<br />
&nbsp; return normalPayAmount();<br />
};<br />
（好处是明显的，可以减少if/else嵌套的数目，从而强烈地提高程序可读性。比较重要的是，需要习惯&ldquo;函数有多个出口&rdquo;这种做法。）<br />
3.18 Replace Conditional with Polymorphism<br />
double getSpeed() {<br />
&nbsp;&nbsp;&nbsp; switch (_type) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case EUROPEAN:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getBaseSpeed();<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case AFRICAN:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return getBaseSpeed() - getLoadFactor() *<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _numberOfCoconuts;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; case NORWEGIAN_BLUE:<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return (_isNailed) ? 0 : getBaseSpeed(_voltage);<br />
&nbsp;&nbsp;&nbsp; }<br />
&nbsp;&nbsp;&nbsp; throw new RuntimeException (&quot;Should be unreachable&quot;);<br />
}<br />
重构为：<br />
&nbsp;<br />
（跟讲Switch那个Bad Smell时举过的例子，基本一样。）<br />
3.19 Introduce Parameter Object<br />
&nbsp;重构为： <br />
3.20 Replace Error Code with Exception<br />
int withdraw(int amount) {<br />
&nbsp;&nbsp;&nbsp; if (amount &gt; _balance) {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return -1;<br />
&nbsp;&nbsp;&nbsp; else {<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _balance -= amount;<br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return 0;<br />
&nbsp;&nbsp;&nbsp; }<br />
}<br />
重构为：<br />
void withdraw(int amount) throws BalanceException {<br />
&nbsp;&nbsp;&nbsp; if (amount &gt; _balance) throw new BalanceException();<br />
&nbsp;&nbsp;&nbsp; _balance -= amount;<br />
}<br />
Why？<br />
1． 提高代码可读性。<br />
2． 方便调用方。调用方可以不再判断返回的Error Code，而只是把异常直接抛出去，待最终接受方处理。比如，类C/S的结构，服务端代码在所有环节都可以直接透传Exception，简化处理流程。Exception最终由客户端统一处理。<br />
（注：有些地方无法完全取代Error Code，比如前台回来的消息处理，onMessage函数。）<br />
3.21 Form Template Method<br />
&nbsp;<br />
重构为：<br />
&nbsp;<br />
（计算金额的步骤，各个子类都一样，即算得基础金额、再算得缴税几多，然后二者想加。于是把这个逻辑上升到父类。子类仅负责其中的子步骤。）<br />
（下面再看一个例子。说明一下Template Method是怎么回事儿。<br />
所有的工作人员，一天的活动，步骤都差不多，无外乎，吃早餐、赶到工作地点&hellip;&hellip;，但不同子类对于各个步骤的实现是不同的。<br />
比如，上午工作，公务员可能是：编写官样文章、聊天、按照规定合理地拒绝刁蛮市民的无理要求&hellip;&hellip;；我司员工可能是：编码、调试、上网看新闻、到匿名论坛发牢骚&hellip;&hellip;；农民工兄弟可能是：扛包、抽烟休息一会、扛包、喝水休息一会&hellip;&hellip;。<br />
比如，吃午餐，公务员是：免费、或者象征性收费的豪华自助餐；我司员工是：别无选择的XLX；农民工兄弟是：其他农民工在廉价出租棚子里制作的不干不净吃了可能得病的方便盒饭。）</font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49107#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:16:25 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49107</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49107</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Divergent Change(发散式变化)、Shotgun Surgery(霰弹式修改)</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49105" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49105</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">Divergent Change(发散式变化)<br />
指的是&ldquo;某一个类受到多种变化的影响&rdquo;，A/B/C/D&hellip;&hellip;多种功能变化的时候它都需要修改。<br />
病因大致是某个类负担了多项任务，太操心了。很可能需要再拆分几个类出来，把变化封装得更细。<br />
以前我写代码的时候有一个例子，曾经有一段时间，P_Unit类处理所有BSC单元的逻辑，但各种单板的逻辑是不一样的，于是DTB改逻辑的时候要修改P_Unit、ABPM改的时候要修改P_UNit、甚至HDLC/UID等逻辑修改的时候P_Unit都要改。显然该类管得太多了。后来，我看了&lt;重构&gt;这本书，痛下决心做了重构。想起来03年，徐峰做配置CAF的时候建议我每个板子一个类，我完全不以为然。显然当初没有理解&ldquo;封装变化&rdquo;这四个字。<br />
&nbsp; <br />
Shotgun Surgery(霰弹式修改)<br />
指的是&ldquo;一个变化引发多个类的修改&rdquo;，完成某个需求的时候，A/B/C/D&hellip;&hellip;多个类都需要修改。<br />
病因大致是多个类之间的耦合太严重。很可能是类没有规划好，没有把变化封装得足够令人满意。<br />
记得水手好像说过，去掉这个Bad Smell不好强求。也有些道理。而且举出Abstract Factory模式作为例证。<br />
但我们要清楚的认识到我们努力的方向，Abstract Factory模式同样不完美，它没有满足Open-Close原则。我们可以在某些条件(包括技术条件)受限的时候写出不完美的代码，但一定要知道它是不完美的。 </font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49105#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:11:21 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49105</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49105</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Bridge模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49103" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49103</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">Bridge模式讲的是把抽象部分和实现部分隔离开，能够实现相互独立发展。<br />
我对Bridge模式依然理解得不是很深入，我盼望书中给我一个简单、清晰的例子来说明该模式的应用，但书本没有能够让我满意，当然也可能是我的问题。<br />
而且，书中的Airplane/AirplaneMaker这个例子放在这里说明Bridge是不恰当的。<br />
Airplane和AirplaneMaker并不能代表Bridge模式中需要的抽象部分和实现部分。这个例子用来说明合成/聚合复用原则还是比较合适的，而且AirplaneMaker和Airplane的关系与&ldquo;职务&rdquo;与&ldquo;员工&rdquo;的关系比较类似，实际上，后一个例子也是出自于合成/聚合复用原则的章节。<br />
希望以后能够有机会更加深入地了解这个桥梁模式。 </font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49103#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:10:14 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49103</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49103</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Facade模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49102" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49102</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">这个模式还是比较有用的，用于解开模块之间的复杂耦合。<br />
从道理上讲，符合&ldquo;内部高内聚、外部松耦合&rdquo;的要求。从实际操作上，各个模块经常分开开发、分开维护，于是使用Facade定义清晰接口，只访问一个门面类，显然好过模块之间的多个类之间的交叉依赖、关联。</font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49102#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:09:17 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49102</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49102</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Flyweight模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49101" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49101</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">该模式的中英文名称之间不是直接翻译的，但表达了这个模式的两个特征，轻量级、共享。<br />
我理解，Flyweight模式就是为系统中需求数量多、但状态不多的轻量级对象建立一个共享实例池。<br />
思路比较容易理解。就不多说了。 </font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49101#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:08:37 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49101</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49101</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Proxy模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49100" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49100</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">大家越来越像了&hellip;&hellip;<br />
从实现形式上看，Decorator模式与Proxy模式之间的区别不大，但从用意上看，前者是想增强方法本身功能、后者是想控制所包含对象的动作。<br />
Proxy模式的一个例子是书中的，在request方法前后增加pre、post方法来做额外工作。<br />
原始类、Proxy类都实现相同的接口，在做了可插入性考虑的系统，Proxy类就可以以原始类的身份被插入系统，原始类的动作就可以被控制，比如在动作之前判断权限、在动作之后记录日志等等。<br />
越来越体会到合成/聚合复用原则的应用。<br />
越来越体会到可插入性的重要。 </font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49100#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:07:43 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49100</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49100</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Decorator模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49098" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49098</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">外部接口没有变化，但内部实现&ldquo;偷偷&rdquo;变化了。其实也不是&ldquo;偷偷&rdquo;，更应该光明正大地告诉人家，你是经过装饰的，虽然都有&ldquo;显示鼻子&rdquo;的接口方法，但你的鼻子可能是垫了东西的。<br />
需要注意的是，修饰过的类和被修饰的类是同类的。比如，实现相同的接口。<br />
装饰过的类要拥有一个未被装饰类的属性。即关联关系。（合成还是聚合我就懒得区分了。）<br />
装饰过的类的方法通常要在未被装饰类的方法基础上做点手脚，以体现装饰。</font></p>
<p><font face="Arial">顺着脑子想到的一个例子，接口PriceGetter，定义了一个方法int getPrice()。<br />
CommonPriceGetter是实现该接口、正常计算价格的。而95DiscountPriceGetter也实现PriceGetter接口，只是计算出来的价格都是打过95折的。具体实现也很容易想到，95DiscountPriceGetter类拥有一个PriceGetter类型的属性，实例化时候塞一个CommonPriceGetter实例给他，getPrice方法在该实例同名方法返回值的基础上乘以0.95返回，即达到目的。<br />
客户端可以任意选择使用那个类实例计算价格，但都是PriceGetter接口的实例，客户端是依赖于抽象的。</font></p>
<p><font face="Arial">书中关于Adapter与Decorator区别的描述也有点意思。<br />
前者是做手脚把让已有类满足其他接口；后者是在已有类实现接口不变的情况下，做手脚使得方法实现发生变化。前者是芯子不变换外观，后者是外观不变换芯子。 </font></p>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49098#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:06:25 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49098</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49098</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Composite模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49097" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49097</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial">个人感觉Composite模式是一个比较牛X的模式。完美地实现了&ldquo;树&rdquo;这一现实实体在OO软件世界的映射。<br />
此模式巧妙之处在于，树叶和枝干实现了同一接口，但树干同时是装载该接口实现类实例的容器，树干可以容纳树叶、同时也可以再容纳树干，于是，一棵数就完美地被描绘出来了。<br />
一个比较典型的例子就是，界面上的Panel是容器的同时、也是控件，可以容纳控件的同时也可以再容纳容器（这里说得就比较罗嗦了，容器本身就是控件嘛）。<br />
但需要注意的是，容器对接口方法的实现需要自律，通常是遍历调用容器内容纳的接口实现类实例的同名方法。<br />
JUnit架构中也有Composite模式的完美应用，TestCase是Test、TestSuite也是Test，但TestSuite是容器、可以容纳Test实现类实例，即，可以容纳TestCase实例和TestSuite实例。于是我们设计测试流程的时候，可以把测试用例任意打包、任意组合、包了再包。<br />
记得以前实现类似算法，每次都要判断是否是叶子、或者优化成比较难以理解的递归算法，总之不是十分理想。<br />
等看到Composite模式的时候真就是相见恨晚了。 </font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49097#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:05:28 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49097</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49097</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Default Adapter模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49096" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49096</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <font face="Arial"><font face="Arial">我觉得把Default Adapter模式和Adapter模式割裂开来，不会影响对Default Adapter模式的理解。<br />
Default Adapter模式就是为目标接口提供一个平庸实现层，真正的实现类从此平庸实现层继承，Override其中对自己有意义的方法，而其他方法保持其平庸状态。<br />
为Target接口所需的方法统统提供一套缺省实现，通常的做法是，除非你特别要求，否则我什么都不做。<br />
如果实现类比较多而且需要实现的方法很多、真正做事儿的方法很少，那么Default Adapter模式会为系统省下不少重复代码。</font></font>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49096#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:04:35 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49096</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49096</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之Adapter模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49095" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49095</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <div><span style="FONT-SIZE: 12px">我对Adapter模式的理解是：<br />
某处有一些需求，可体现为Target接口（不妨假定Target有两个方法，m1、m2）。<br />
我们在满足该需求的时候，即构造类来实现Target接口的时候，很容易想到的是看看是否存在已有资源可被利用（重用）。<br />
比方说，此时我们发现Adaptee类实现了方法m1，如何重用？<br />
<br />
两种重用方式分别对应于Adapter模式的两种形态：<br />
1 继承的方式&mdash;&mdash;类的Adapter模式<br />
Adapter类从Adaptee类继承，于是自然拥有了方法m1。再自行实现方法m2，便完成了对Target接口的实现。<br />
2 合成/聚合的方式&mdash;&mdash;对象的Adapter模式<br />
Adapter拥有一个Adaptee类型的属性，方法m1的实现委托给该属性实例的方法m1来做。再自行实现方法m2，也完成了对Target接口的实现。<br />
<br />
哪种方式好呢？我强烈认为后者好些。满足合成/聚合复用原则。<br />
事实上，后者确实更加灵活，比如Adaptee所拥有的方法m1名字叫做m3，但其实现的功能与Target要求的方法m1完全一样，或者只需稍微转换一下输出结果的格式。那么类的Adapter模式就不适用了，而对象的Adapter模式依然可以面带微笑。<br />
<br />
总之，我认为Adapter模式是基于重用考虑的一种模式。<br />
你要什么（接口），我就给你什么（实现类），我从哪里攒叨出来的方法实现，你就不用关心了（封装实现逻辑、实现方式）。你只需知道我是你所需接口的实现类。</span> </div>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49095#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:02:49 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49095</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49095</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之创建类模式</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49094" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49094</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">周末再翻《Java与模式》，说说对创建类模式的一点理解。大家交流。</font></p>
<p><font face="Arial">创建类模式，我主要关注的是Simple Factory、Factory Method、Builder这几个。<br />
当然，其他一些模式可能更加常用，比如Singleton、Prototype，但比较简单，不涉及整体脉络，此处略去不述。</font></p>
<p><font face="Arial">首先，说说Simple Factory。<br />
创建类模式，都是对实例创建过程的封装。<br />
Simple Factory，是最容易想到的封装方式，Client无需知道某类的instance是怎么弄出来的，直接跟工厂要实例就行了，而且是静态方法，调用起来也方便。此时，工厂(书中叫做Creator)挑起重担，何时创建什么实例、如何创建全部由他来操办。<br />
当工厂的担子越来越重时，比如，产品种类猛增、各个产品实例的创建过程都比较复杂、判断创建何种产品实例的逻辑也越来越复杂，工厂的改动日趋频繁，而且严重地违反了Open-Close法则，不同产品类的创建代码互相影响，这就说明对变化的封装没有达到应用的效果，产品A的变化影响到了产品B。对Simple Factory的优化产生了Factory Method。</font></p>
<p><font face="Arial">Factory Method。<br />
不同产品的创建过程既然都有着各不相同的单独逻辑，很容易想到把这些各自繁衍的变化封装起来，于是，不同的产品由配套的Creator来创建实例。此时，系统更加复合Open-Cloase法则，增加了新产品，同时增加相应的Creator，他们都位于继承结构的叶子端，不影响枝干和其他兄弟叶子。<br />
但，此时，Client就需要知道哪个产品是使用哪个Creator来获得实例的了。让Client知道得多了，并不一定是坏事，个人感觉这里的情况是更加符合接口隔离原则，获得了该原则带来的优势。</font></p>
<p><font face="Arial">Abstract Factory。<br />
用于产品系列，个人不是很喜欢这个模式。当然也欢迎大家讨论。该模式此处不述。</font></p>
<p><font face="Arial">Builder。<br />
如果某类的实例创建需要固定的几个步骤(我理解为几道工序或者几个零件)，想到将生产、组装过程分开(脱开耦合、增加可插入性)，再参考Template Method模式的思路，就产生了Builder模式。</font></p>
<p><font face="Arial">再罗索一遍，创建类模式都是对实例创建过程的封装，不同模式适用于不同情况，使用得是否得当我觉得就是看对变化的封装做得好不好。</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49094#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 15:01:41 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49094</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49094</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之软件质量属性</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49093" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49093</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial">以前写邮件的时候，很多同事都说软件产品的质量属性太多。</font></p>
<p><font face="Arial">周末重看《Java与模式》，发现阎宏博士的一些简短归纳，感觉有些道理，可作参考。</font></p>
<p><font face="Arial">阎宏认为，比较重要的质量属性为可维护性和可重用性。可维护性又分为：可扩展性、灵活性、可插入性。<br />
我认为，可维护性，分为：可读性、可扩展性、可修改性、可插入性，将更加圆整、更加容易理解。<br />
首先，代码要可读，可读才可理解，可理解才可维护。其余的可扩展性、可修改性、可插入性是对系统增加新零件、修改原有零件、更换原有零件的支持，支持了这三种对系统的维护方式，系统当然就可维护了。</font></p>
<p><font face="Arial">另外，我觉得还有一个比较重要的质量属性，是可测试性。不过，怎么样才更加可测试？我还暂时还没有让自己满意的想法。<br />
一般来讲，可插入性好会比较容易测试，因为可以较容易地插入Mock对象模拟系统行为。其次，变化封装得好将更加容易测试，否则，多种干着不同事情的逻辑混杂在一个方法中，显然不容易测试。</font></p>
<p><font face="Arial">参考文献：阎宏《Java与模式》<font face="Arial"></font></font></p>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49093#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 14:58:33 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49093</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49093</guid>
      </item>
      <item>
        <title>“学习OO好榜样”之面向对象设计原则</title>
        <author>王杲杲</author>
        <description>
          <![CDATA[
          <br/>
          作者: <a href="http://wang-zhenyu.javaeye.com">王杲杲</a>&nbsp;
          链接：<a href="http://wang-zhenyu.javaeye.com/blog/49092" style="color:red;">http://wang-zhenyu.javaeye.com/blog/49092</a>&nbsp;
          发表时间: 2007年01月22日
          <br/><br/>
          声明：本文系JavaEye网站发布的原创博客文章，未经作者书面许可，严禁任何网站转载本文，否则必将追究法律责任！
          <br/><br/>
          <p><font face="Arial"><font face="Arial">Open-Close原则<br />
是一个愿景性质的原则，如果系统能够达到Open-Close原则描述的情形就比较理想了，对扩展开放、对修改关闭，即，不修改原有代码即可完成对系统的扩展。<br />
实现Open-Closed原则，抽象化是关键。<br />
抽象层，因为抽象所以稳定。不变应万变，不用修改，满足Open-Closed原则的Closed一头。<br />
抽象层的具体实现层可以满足扩展要求，满足Open-Closed原则的Open一头。<br />
Open-Closed原则还可表述为&ldquo;对可变性的封装&rdquo;原则。&ldquo;找到一个系统的可变因素，将它封装起来。&rdquo;<br />
一个可变性因素，不应该被散落在各个角落，而应该被封装到一个对象中。<br />
一种可变性因素，不应该与另一种可变性因素混和在一起，而应各自独立开。<br />
但，单从原则本身来说，它并没有告诉我们如何才能够让系统满足这个原则。</font></font></p>
<p><font face="Arial">里氏代换原则<br />
<font face="Arial">指导我们如何去构建一个extends(继承、派生)结构。<br />
子类与父类的关系必须是is-A，即，子类必须在任何场合都敢于大声宣称自己起码(至少)是一个父类。比如，假设某类结构，&ldquo;男人&rdquo;、&ldquo;女人&rdquo;从&ldquo;人&rdquo;派生出来，看起来就是满足里氏代换原则的，因为无论&ldquo;男人&rdquo;还是&ldquo;女人&rdquo;，在任何场合都是&ldquo;人&rdquo;。这个原则大多数情况下，可以用现实世界中的概念来思考，但软件世界与显示世界毕竟有区别，比如，书中的例子，&ldquo;正方形是不是矩形&rdquo;问题。<br />
此外，很多问题需要利用OO核心思想来灵活考虑，还是书中的例子(我只说大概意思，可能与书中描述存在差异)，一个类结构，&ldquo;职工、普通职员、项目经理、科长、部长&hellip;&hellip;&rdquo;，从&ldquo;员工&rdquo;类派生出来，从一般概念来看还不错，职工和部长都是员工嘛，但这里隐含问题，现实世界中，普通职员可能变成项目经理，但软件世界中，普通职员和项目经理被规划成两个类了，于是一个普通职员instance是很难变成项目经理instance的，这说明我们把显示世界映射为软件世界时，出现了问题。更加合理的做法是，把这些职务(角色)抽象出来，比如叫做&ldquo;职务&rdquo;类(interface/abstract class)，所有职务从其派生，员工类、职务类是关联关系，任何一个员工实例都一个职务实例作为它的属性，这样就对了，员工的职务是可以变化的。实现这个重构的依据，是OO中的封装变化思想，以及从中演化出来的依赖倒换原则、合成/聚合复用原则。<br />
但凡涉及到extends结构的设计模式都符合着里氏代换原则：<br />
策略模式：一组算法，把他们封装成对象，使之可以互换（满足同一接口，即都is-A这个接口）。<br />
合成模式：Leaf和Composite都is-A Component，于是才可能方便地层层嵌套。<br />
代理模式：Proxy与RealSubject都is-A父类Subject，于是可以插入代理，完成附加功能。<br />
&hellip;&hellip;</font></font></p>
<p><font face="Arial">依赖倒换原则<br />
很具体地指导我们对抽象类(接口)、实现类的使用。<br />
依赖于抽象的实体(interface/abstract class)，才能够更具有可插入性(但凡实现既有接口的实现类实例都可以在依赖此接口的地方以此接口实例的角色插入进来)，更容易满足Open-Close原则(抽象的层次不变化、实现的层次由于使用不同的类来封装不同的变化，于是可以在增加新类作为扩展的同时不需要修改已有实现类)。</font></p>
<p><font face="Arial"><font face="Arial">接口隔离原则<br />
这个原则比较孤立，也是从OO封装变化思想演化出来的，要将变化封装到最&ldquo;贴身&rdquo;。比如，A/B接口可能在大多数情况下都由同一个实现类提供，但某些情况下，B接口都有些实现类是没有意义的，这时候就需要把A/B分开作为两个接口，某些类实现全部A/B接口、某些类仅实现A接口。A/B单独变化，于是把A/B单独封装，接口隔离。</font></font></p>
<p><font face="Arial"><font face="Arial">合成/聚合复用原则<br />
与里氏代换原则关系较为紧密，里氏代换原则告诉我们什么情况下使用extends，在不满足里氏代换原则时，还想达到重用的目的，就引出合成/聚合复用原则。上文中，员工与职务的例子，来说明这个事儿就比较合适。<br />
从复用角度来说：&ldquo;合成/聚合复用&rdquo;比&ldquo;继承&rdquo;复用灵活。前者是动态复用（因而具有可插入性）、后者是静态复用（编译时就固定了复用关系），而且后者的复用有&ldquo;不支持多重继承&rdquo;的限制。</font></font></p>
<p><font face="Arial"><font face="Arial">迪米特法则<br />
用于解开类之间的不必要的耦合。&ldquo;不要与陌生人说话&rdquo;。说起来容易，实际操作的时候很可能出现些无所适从的问题，而解开类之间的耦合是比较重要的，目前我们设计类的时候，增加属性、增加对其他类的调用都比较随意，不太好。<br />
迪米特法则要求：一个对象应当对其他对象有尽可能少的了解。几种其他的表述：只与你直接的朋友通信、不要跟&ldquo;陌生人&rdquo;说话（冯远征？）<br />
每个软件单位对其他单位都具有最少的知识，而且局限于那些与本单位密切相关的软件单位。<br />
狭义迪米特法则-规定了谁是Friends、谁是Stranger。Friends圈子包括：<br />
当前对象自身（this）、Instance field（如果field是Map、List等容器类型，则容器内的对象也是朋友）、当前对象创建的对象（调用其构造方法）、当前对象方法的参数对象。<br />
只跟Friends说话，跟Stranger说的话由Friends转述。<br />
狭义迪米特法则的弊端：传递间接调用的小方法太多！解决办法：遵循依赖倒换原则做些折衷处理，让对象依赖于Stranger的抽象层。虽然没有完全断开耦合，至少降低了耦合。</font></font></p>
<p><font face="Arial">小结<br />
Open-Close原则是比较总体的要求、是愿景。<br />
实现Open-Close原则的关键，是抽象。<br />
依赖倒换原则就是强调抽象的。<br />
有了抽象层，就要有实现层，实现层无疑要从抽象层extends/implements，实现层/抽象层的关系，要依从里氏代换原则。<br />
很多情况不满足里氏代换原则，又要实现复用，于是引出，合成/聚合复用原则。<br />
两外两个原则是说类之间(接口)关系的。<br />
接口隔离原则，要求类之间的接口更加狭窄，更加确切、更加合身地封装变化。<br />
迪米特法则，要求类之间的接口应该发生在哪些类之间，不应该发生在哪些类之间。帮助我们解开类之间的耦合。 </font></p>
<p><font face="Arial">参考文献：<br />
阎宏《Java与模式》<br />
Meilir Page-Jones《UML面向对象设计基础》</font></p>
          <br/>
          <span style="color:red;">
            <a href="http://wang-zhenyu.javaeye.com/blog/49092#comments" style="color:red;">本文的讨论也很精彩，浏览讨论>></a>
          </span>
          <br/><br/><br/>
          <span style="color:#E28822;">JavaEye推荐</span>
          <br/>
          <ul class='adverts'><li><a href='/adverts/42' target='_blank'><span style="color:red;font-weight:bold;">搜狐网站诚聘Java、PHP和C++工程师</span></a></li><li><a href='/adverts/41' target='_blank'><span style="color:red;font-weight:bold;">北京: 千橡集团暨校内网诚聘软件研发工程师</span></a></li></ul>
          <br/><br/><br/>
          ]]>
        </description>
        <pubDate>Mon, 22 Jan 2007 14:55:21 +0800</pubDate>
        <link>http://wang-zhenyu.javaeye.com/blog/49092</link>
        <guid>http://wang-zhenyu.javaeye.com/blog/49092</guid>
      </item>
  </channel>
</rss>