﻿<?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/raimundox/category/5762.html</link><description>知天之所为，知人之所为者，至矣。知天之所为者，天而生也；知人之所为者，以其知之所知以养其知之所不知，终其天年而不中道夭者：是知之盛也。</description><language>zh-cn</language><lastBuildDate>Tue, 20 Apr 2010 10:10:13 GMT</lastBuildDate><pubDate>Tue, 20 Apr 2010 10:10:13 GMT</pubDate><ttl>60</ttl><item><title>Misquotation</title><link>http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Wed, 28 Nov 2007 10:08:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/163761.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/163761.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/163761.html</trackback:ping><description><![CDATA[前几天在JavaEye海阔被标题党阴了一把，看了一篇转的文章叫《<a href="http://bbs.education.163.com/bbs/newht/5009.html">被中国人误传了数千年的七句话</a>》，颇有些哭笑不得的感慨：<br />
<br />
1. 这些话的确是被误传了不假，但是最多也就一百年吧。中国知识分子不读四书五经史子集的坏风气大抵是开始于所谓的新文化运动吧。再往前的人，对于这些典籍字字爬梳，提了上句马上背下句，就算是以章句式解读为主的宋元，也不应该随随便便就被忽悠了，更不用说反对宋儒理学讲究正本清源的明清了。<br />
<br />
2. 古人断章取义是一种风雅的言谈习惯，所谓&#8220;雅言&#8221;是要字字出典的，有点像对暗号。比如我们家猫跑了，搁古代我肯定问&#8220;谁之过欤？&#8221;，十有八九会回答说，&#8220;言是典守者之过也&#8221;，这句射的是&#8220;虎兕出于柙&#8221;，正好应景。甚至为了诙谐应景，故意曲解文义的情况也是很常见的。如果以此为证说误传的话，恐怕只能算是牛嚼牡丹了。顺便多说一句，其实这个毛病现代人也有，不过不再是古文了，大多数是电影电视台词：&#8220;空气在颤抖仿佛天空在燃烧。是啊，暴风雨就要来了&#8221;，&#8220;道哥，牌子啊&#8221;，&#8220;你看我的英语，有没有长进&#8221;之类的，虽不复古韵，但也还算有趣。<br />
<br />
<br />
P.S. : 今天team里有人把David Wheeler的名言，贴在了Quote Wall上：&#8220;Any problem in computer science can be solved with another layer of indirection.&#8221;<br />
<br />
这到的确算是一句被误传的名言吧，原文是&#8220;Any problem in computer science can be solved with another layer of indirection. <strong>But that usually will create another problem.</strong>&#8221;<br />
<img src ="http://www.blogjava.net/raimundox/aggbug/163761.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2007-11-28 18:08 <a href="http://www.blogjava.net/raimundox/archive/2007/11/28/163761.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Feng Shui for Standard ML Programmers</title><link>http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 10 Jul 2007 13:53:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/129436.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/129436.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/129436.html</trackback:ping><description><![CDATA[<a>http://www.dcs.ed.ac.uk/home/stg/fengshui.ps.gz</a><br><br>今天早上打开Google Reader就看见这么一篇，内容倒也罢了，不过是bad smell的另一个名字而已，硬要扯上分水也只能算是勉勉强强。不过郁闷的是，竟然是个洋人的手笔，国学不昌实不能不令我辈心忧啊。<br><br>p.s. 预计未来6个月口头禅："你这写当心坏了项目的风水"<br><img src ="http://www.blogjava.net/raimundox/aggbug/129436.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2007-07-10 21:53 <a href="http://www.blogjava.net/raimundox/archive/2007/07/10/129436.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>The Keyword 'end' Drives Me Crazy</title><link>http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Fri, 11 May 2007 12:32:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/116864.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/116864.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/116864.html</trackback:ping><description><![CDATA[最近很多时间都在用Ruby，逐渐地发现了一件很不爽的事情，就是Ruby的end关键字。block多套几层，很容易就最后一页都是end了...难怪有人说，ruby不过是另一种acceptable Lisp，&#8220;最后一页都是括号&#8221;的经典标志以另外一种形式复现了...对于Lisp的括号，我还是可以接受的，但是满眼的end，直接让我回忆起10年前冲刺NOI的种种，CPU直接切换到实模式，什么可读啊小粒度方法全都没有了，审美观赤裸地变为短小精悍...最后杀红了眼，一行算出文法定义的所有nullable symbols...<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;">1</span><span style="color: #000000;">&nbsp;</span><span style="color: #0000ff;">while</span><span style="color: #000000;">&nbsp;@productions.inject(</span><span style="color: #0000ff;">false</span><span style="color: #000000;">)&nbsp;{</span><span style="color: #000000;">|</span><span style="color: #000000;">c,&nbsp;p</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;c&nbsp;</span><span style="color: #000000;">|=</span><span style="color: #000000;">&nbsp;</span><span style="color: #000000;">!</span><span style="color: #000000;">nullable</span><span style="color: #000000;">?</span><span style="color: #000000;">(p.nonterminal)&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;p.symbols.all</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;{</span><span style="color: #000000;">|</span><span style="color: #000000;">s</span><span style="color: #000000;">|</span><span style="color: #000000;">&nbsp;nullable</span><span style="color: #000000;">?</span><span style="color: #000000;">&nbsp;s}&nbsp;</span><span style="color: #000000;">&amp;&amp;</span><span style="color: #000000;">&nbsp;@nullables&nbsp;</span><span style="color: #000000;">&lt;&lt;</span><span style="color: #000000;">&nbsp;p.nonterminal}</span></div>
<br>注意1不是行号...这句用的statement modifier, 1是我能想到的最小ruby语句了...<br><br>p.s. <br>我现在已经恢复到OO保护模式了...刚才追求短小过了头的同时，发现了ruby bulid-in object的一个陷阱...<br>a = Array.new 5, []<br>[[],[],[],[],[]]<br>a[0] &lt;&lt; 1<br>[[1],[1],[1],[1],[1]]<br><br>想不到华丽的Array直接假设传进去的都是值对象了，好歹您也调个dup啊...<br><br><br>  <img src ="http://www.blogjava.net/raimundox/aggbug/116864.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2007-05-11 20:32 <a href="http://www.blogjava.net/raimundox/archive/2007/05/11/116864.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Church Number</title><link>http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Sun, 08 Oct 2006 18:32:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/73931.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/73931.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/73931.html</trackback:ping><description><![CDATA[今天被老庄拉到JavaEye扯皮，扯来扯去还是lambda演算...本来应承了老庄写lambda演算简介，不过看到磐石T1同学提到了Church number来勾引whl同学...于是我想还是写一些更有意思的东西吧。<br /><br />每个Church number都是一个接受两个参数的函数，这两个参数又都是函数，第一个参数称为后继函数，第二个参数则叫做零点函数。依据这两个函数，我们可以定义Church number zero, one, two：<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%;"><font color="#000000"><span style="color: rgb(0, 0, 0);">(define zero  (lambda (successor zero) zero))<br />(define one （lambda (successor zero) (successor zero)))<br />(define two   (lambda (successor zero) (successor (successor zero))))<br /></span></font></div><br />可以看出，所谓one就是对零点函数应用一次后继函数，而two则是对零点函数应用后继函数的结果再次应用后继函数，依次类推可以得到Church Number n。下面我们可以通过后继函数increase和零点函数f(x) = 0来看看这些Church Number的计算结果：<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);">(define (increase x) (</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> x </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">))<br /><br />(zero increase 0)<br />&gt; 0<br /></span><span style="color: rgb(0, 0, 0);">(one increase 0)</span><br /><span style="color: rgb(0, 0, 0);">&gt;1<br /></span><span style="color: rgb(0, 0, 0);">(two increase 0)</span><br /><span style="color: rgb(0, 0, 0);">&gt;2<br /><br />an approximate Java version:<br /><br />public interface Function&lt;T&gt; {<br />    T apply(Object... parameters);<br />}<br /><br />public interface ChurchNumber {<br />    Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero);<br />}<br /><br />ChurchNumber zero = new ChurchNumber() {<br />   public Integer apply(Function&lt;Integer&gt; successor,  Function&lt;Integer&gt; zero) {<br />      return zero.apply();<br />   }<br />};<br /><br />ChurchNumber one = new ChurchNumber() {<br />   public Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero) {<br />      return successor.apply(zero);<br />   }<br />};<br /><br />ChurchNumber two = new ChurchNumber() {<br />   public Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero) {<br />      return successor.apply(successor.apply(zero));<br />   }<br />};<br /><br />Function increase = new Function&lt;Integer&gt;() {<br /> public Integer apply(Object... parameters) {<br />   if (parameters[0] instanceof Function) {<br />      return ((Function&lt;Integer&gt;) parameters[0]).apply() + 1;<br />   }<br />   return (Integer) parameters[0] + 1;<br /> }<br />};<br /><br />Function numberZero = new Function&lt;Integer&gt;() {<br />   public Integer apply(Object... parameters) { return 0;}<br />};<br /><br /><br />System.out.println(zero.apply(increase, numberZero));<br />&gt;0<br />System.out.println(one.apply(increase, numberZero));<br />&gt;1<br />System.out.println(two.apply(increase, numberZero));<br />&gt;2<br /></span></div><br />定义了Church number后，我们继续定义Church number上的运算，首先是增加1：<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);">(define (inc x) (lambda </span><span style="color: rgb(0, 0, 0);">(successor zero) (successor (x successor zero))</span><span style="color: rgb(0, 0, 0);">))<br /><br />(define three (inc two))<br />(three increase 0)<br />&gt;3<br /><br /></span><span style="color: rgb(0, 0, 0);">an approximate Java version:</span><br /><span style="color: rgb(0, 0, 0);"><br />static ChurchNumber inc(final ChurchNumber churchNumber) {<br />   return new ChurchNumber() {<br />      public Integer apply(Function&lt;Integer&gt; successor, Function&lt;Integer&gt; zero) {<br />         return successor.apply(churchNumber.apply(successor, zero));<br />       }<br />   };<br />}<br /><br />ChurchNumber three = inc(two);<br />System.out.println(three.apply(increase, numberZero));<br />&gt;3<br /></span></div><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, 0);">(define (add x y) (lambda (</span><span style="color: rgb(0, 0, 0);">successor zero</span><span style="color: rgb(0, 0, 0);">)  (x successor (y successor zero))))<br /><br />(define five (add three two))<br />(five increase 0)<br />&gt;5<br /><br /></span><span style="color: rgb(0, 0, 0);">an approximate Java version:</span><br /><span style="color: rgb(0, 0, 0);"><br />static ChurchNumber add(final ChurchNumber x, final ChurchNumber y) {<br />        return new ChurchNumber() {<br />            public Integer apply(final Function&lt;Integer&gt; successor,<br />                    final Function&lt;Integer&gt; zero) {<br />                return x.apply(successor, new Function&lt;Integer&gt;() {<br />                    public Integer apply(Object... parameters) {<br />                        return y.apply(successor, zero);<br />                    }<br />                });<br />            }<br />        };<br />}<br /><br />ChurchNumber five = add(two, three);<br />System.out.println(five.apply(increase, numberZero));<br />&gt;5<br /></span></div><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);">(define (multiply x y) </span><span style="color: rgb(0, 0, 0);">(lambda (</span><span style="color: rgb(0, 0, 0);">successor zero</span><span style="color: rgb(0, 0, 0);">)  (x  (lambda (z) (y successor z)) zero)))<br /><br />(define four (multiply two two))<br />(four increase 0)<br />&gt;4<br /><br /></span><span style="color: rgb(0, 0, 0);">an approximate Java version:</span><br /><span style="color: rgb(0, 0, 0);"><br />static ChurchNumber multiply(final ChurchNumber x, final ChurchNumber y) {<br />        return new ChurchNumber() {<br />            public Integer apply(final Function&lt;Integer&gt; successor,<br />                    Function&lt;Integer&gt; zero) {<br />                return x.apply(new Function&lt;Integer&gt;() {<br />                    public Integer apply(final Object... parameters) {<br />                        return y.apply(successor, new Function&lt;Integer&gt;() {<br />                            public Integer apply(Object... ignoredParameters) {<br />                                if (parameters[0] instanceof Function) {<br />                                    return ((Function&lt;Integer&gt;) parameters[0]).apply();<br />                                }<br />                                return (Integer) parameters[0];<br />                            }<br />                        });<br />                    }<br />                }, zero);<br />            }<br />        };<br />}<br /><br />ChurchNumber four = multiply(two, two);<br />System.out.println(four.apply(increase, numberZero));<br /></span></div><br />没有减法和除法，Church当年发明这套东西的时候就没有。原因是非常明显的...因此Church number只有后继函数，而没有前驱函数。也就是说Church number只能往前数...不能望后数...自然不可能作出减法和除法了。当然扩展一下也是非常容易的：<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);">(define negative</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">one (lambda (successor precursor zero) (precursor zero)))<br />(define one (lambda (successor precursor zero) (successor zero)))<br /><br />(define (add x y) (lambda (successor precursor zero) (x successor precursor ( y successor precursor zero) )))<br /><br />(define (inc x) (</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> x </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">))<br />(define (dec x) (</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);"> x </span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);">))<br /><br />(define zero (add one negative</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">one))<br /><br />(zero inc dec </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">)<br /></span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br /></span></div><br /><br />whl同学问这样能不能实现浮点，答案是可以实现有限精度的浮点数....因为按照这个思路发展下去，我们定义浮点的successor和precursor函数只能在有限的位数之内...当然有了one,zero再结合pair，模拟0/1存储实现浮点也不是不可能的事情...<font color="#ffffff"><span style="color: rgb(0, 0, 0);"></span><span style="color: rgb(0, 0, 0);"></span></font><img src ="http://www.blogjava.net/raimundox/aggbug/73931.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-10-09 02:32 <a href="http://www.blogjava.net/raimundox/archive/2006/10/09/73931.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Selenium Better Pratice</title><link>http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Fri, 04 Aug 2006 13:59:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/61860.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html#Feedback</comments><slash:comments>11</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/61860.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/61860.html</trackback:ping><description><![CDATA[
		<p>1. Never use Selenium FIT mode</p>
		<p>Selenium分为两种运行模式，Driven Mode(现在叫Selenium Remote Control)和FIT Mode(现在叫Selenium Core)。</p>
		<p>FIT Mode顾名思义，就是类似FIT Testing Framework那种使用方式，主要用于QA等非技术人员编写Web应用的功能测试。FIT Mode的Selenium测试使用HTML来组织测试用例。例如我要测试一个web应用的登陆功能。我可能写出这样的HTML 表格。</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">table</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 2</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 3</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">open</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 4</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">http://localhost:8080/login</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 5</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">type</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 9</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">id=username</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">10</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">someuser</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">11</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">12</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">type</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">id=password</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">15</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">password</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">16</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">17</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">18</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">click</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">19</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">id=login_button</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">20</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">21</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">22</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">23</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" /> </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">assertTextPresent</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">24</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">Welcome to xxxx</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">25</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />        </span>
				<span style="COLOR: #0000ff">&lt;</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;&lt;/</span>
				<span style="COLOR: #800000">td</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">26</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">tr</span>
				<span style="COLOR: #0000ff">&gt;</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">27</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">&lt;/</span>
				<span style="COLOR: #800000">table</span>
				<span style="COLOR: #0000ff">&gt;</span>
		</div>
		<p>不同于FIT，Selenium内置了一系列的命令，如上例中的open, type, click以及assertTextPresent，因此QA可以完全抛开DEV独立地编写测试(FIT需要DEV提供Behavior Fixture)。因此FIT Mode是相当容易使用的，哪怕不会使用HTML的QA，也可以使用FrontPage画出三列表格，依次填入数据。</p>
		<p>然而对于大多数team而言——尤其是敏捷team，FIT Mode平易的外表下是令人恐惧的泥沼。大多数团队往往选择使用Selenium作为功能测试和集成测试工具而不仅仅是QA测试工具，在不同的迭代间遇到功能流程或UI变化时，必须要重构Selenium测试，或者说，Functional Test Migration。令人遗憾的是，HTML based的Selenium FIT Testing的重构竟然令人难以置信的困难。我们可以使用include等Selenium FIT扩展，使得它可以重用详细的功能（Log in， Log out诸如此类）。即便如此，在一个真实的项目中，Selenium Test的数量往往在200-500之间(我目前所处的项目在改用Driven Mode前已达350+)，对于这么大基数的Selenium测试，手工重构几乎是不可想象的，而目前尚没有HTML代码重构工具。即便存在泛泛意义上的HTML重构工具，对于Selenium测试重构的有效性尚待商榷。而使用Driven Mode上述代码可以写为:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img id="Codehighlighter1_61_302_Open_Image" onclick="this.style.display='none'; Codehighlighter1_61_302_Open_Text.style.display='none'; Codehighlighter1_61_302_Closed_Image.style.display='inline'; Codehighlighter1_61_302_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_61_302_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_61_302_Closed_Text.style.display='none'; Codehighlighter1_61_302_Open_Image.style.display='inline'; Codehighlighter1_61_302_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> testShouldShowAWeclomeMessageAfterUserLoggedIn() </span>
				<span id="Codehighlighter1_61_302_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_61_302_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">2</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.open(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">http://localhost:8080/login</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">3</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=username</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">someuser</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.click(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=login_button</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">6</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    assertTrue(selenium.isTextPresent(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Welcome to xxxx</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">));<br /></span>
						<span style="COLOR: #008080">7</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>
				<br />很自然，一个训练有素的程序员会重构出如下代码:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img id="Codehighlighter1_52_231_Open_Image" onclick="this.style.display='none'; Codehighlighter1_52_231_Open_Text.style.display='none'; Codehighlighter1_52_231_Closed_Image.style.display='inline'; Codehighlighter1_52_231_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_52_231_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_52_231_Closed_Text.style.display='none'; Codehighlighter1_52_231_Open_Image.style.display='inline'; Codehighlighter1_52_231_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> login(String username, String password) </span>
				<span id="Codehighlighter1_52_231_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_52_231_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 2</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.open(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">http://localhost:8080/login</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080"> 3</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=username</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,username);<br /></span>
						<span style="COLOR: #008080"> 4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, password);<br /></span>
						<span style="COLOR: #008080"> 5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium.click(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=login_button</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">); <br /></span>
						<span style="COLOR: #008080"> 6</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 8</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_295_391_Open_Image" onclick="this.style.display='none'; Codehighlighter1_295_391_Open_Text.style.display='none'; Codehighlighter1_295_391_Closed_Image.style.display='inline'; Codehighlighter1_295_391_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_295_391_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_295_391_Closed_Text.style.display='none'; Codehighlighter1_295_391_Open_Image.style.display='inline'; Codehighlighter1_295_391_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> testShouldShowAWeclomeMessageAfterUserLoggedIn() </span>
				<span id="Codehighlighter1_295_391_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_295_391_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 9</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    login(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">someuser</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">10</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    assertTrue(selenium.isTextPresent(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Welcome to xxxx</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">));<br /></span>
						<span style="COLOR: #008080">11</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>之后无论是pull up到公共基类还是extact到Utils class都是很容易的事情。由于Java在代码重构上便利，Java Selenium Remote Control成为使用Selenium的最佳方式。在这一点上，纵使Ruby语法上比Java简单灵活得多，它仍不是编写Selenium测试的最佳载体(当然一个经过精心设计的ruby selenium dsl wrapper还是具有非凡的价值的，这个我们后面会涉及到)。</p>
		<p>2. Using the name user, system, page instead of selenium</p>
		<p>观察上面提到的代码，其中使用selenium来操纵web应用的行为，这在Remote Control里是常见的做法，但是仍然不够好，我们可以做一些小的变化以得到更好的测试:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080"> 1</span>
				<img id="Codehighlighter1_23_127_Open_Image" onclick="this.style.display='none'; Codehighlighter1_23_127_Open_Text.style.display='none'; Codehighlighter1_23_127_Closed_Image.style.display='inline'; Codehighlighter1_23_127_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_23_127_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_23_127_Closed_Text.style.display='none'; Codehighlighter1_23_127_Open_Image.style.display='inline'; Codehighlighter1_23_127_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">protected</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> setup() </span>
				<span id="Codehighlighter1_23_127_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_23_127_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 2</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    selenium </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> <img src="http://www.blogjava.net/images/dot.gif" /><img src="http://www.blogjava.net/images/dot.gif" /> </span>
						<span style="COLOR: #008000">//</span>
						<span style="COLOR: #008000"> intialize selenium instance</span>
						<span style="COLOR: #008000">
								<br />
						</span>
						<span style="COLOR: #008080"> 3</span>
						<span style="COLOR: #008000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />
						</span>
						<span style="COLOR: #000000">    user </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> selenium;<br /></span>
						<span style="COLOR: #008080"> 4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    currentPage </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> selenium;<br /></span>
						<span style="COLOR: #008080"> 5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080"> 6</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080"> 7</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_182_345_Open_Image" onclick="this.style.display='none'; Codehighlighter1_182_345_Open_Text.style.display='none'; Codehighlighter1_182_345_Closed_Image.style.display='inline'; Codehighlighter1_182_345_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_182_345_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_182_345_Closed_Text.style.display='none'; Codehighlighter1_182_345_Open_Image.style.display='inline'; Codehighlighter1_182_345_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> login(String username, String password) </span>
				<span id="Codehighlighter1_182_345_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_182_345_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080"> 8</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.open(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">http://localhost:8080/login</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080"> 9</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=username</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">,username);<br /></span>
						<span style="COLOR: #008080">10</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.type(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, password);<br /></span>
						<span style="COLOR: #008080">11</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    user.click(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">id=login_button</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">); <br /></span>
						<span style="COLOR: #008080">12</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
				<span style="COLOR: #000000">
						<br />
				</span>
				<span style="COLOR: #008080">13</span>
				<span style="COLOR: #000000">
						<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
						<br />
				</span>
				<span style="COLOR: #008080">14</span>
				<span style="COLOR: #000000">
						<img id="Codehighlighter1_409_508_Open_Image" onclick="this.style.display='none'; Codehighlighter1_409_508_Open_Text.style.display='none'; Codehighlighter1_409_508_Closed_Image.style.display='inline'; Codehighlighter1_409_508_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
						<img id="Codehighlighter1_409_508_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_409_508_Closed_Text.style.display='none'; Codehighlighter1_409_508_Open_Image.style.display='inline'; Codehighlighter1_409_508_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				</span>
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> testShouldShowAWeclomeMessageAfterUserLoggedIn() </span>
				<span id="Codehighlighter1_409_508_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_409_508_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">15</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    login(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">some guy</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">, </span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">password</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">);<br /></span>
						<span style="COLOR: #008080">16</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />    assertTrue(currentPage.isTextPresent(</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">Welcome to xxxx</span>
						<span style="COLOR: #000000">"</span>
						<span style="COLOR: #000000">));<br /></span>
						<span style="COLOR: #008080">17</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>基本上这只不过是"另一种写法"而已，但是它更好的表达了"用户的行为"，如login代码所示。以及"系统的正确相应"，即currentPage.isTextPresent()。这种是典型的对编译器无意义对人有意义的代码，也就是普遍意义上好的代码。</p>
		<p>3. Creating a DSL base on your test codes</p>
		<p>懂得HTML的QA可以在没有DEV的帮助下使用Selenium FIT mode，然而却不能在没有DEV的帮助下使用Driven Mode。于是最自然也是最fashion的做法，就是在已有的test codes之上提供Testing DSL或者Scripting Language，让FIT mode变得更加FIT。这方面内容是一个更大的主题，以后再详细展开吧。</p>
		<p>4. Hacking Selenium Object to support FIT command</p>
		<p>Selenium FIT mode和RC mode下的命令有些许差异，比如FIT中的assertTextPresent，在RC中变成了isTextPresent。同样还有FIT中最实用的命令clickAndWait，在RC中变成了click和waitForPageToLoad。在RC中使用FIT mode中的命令也非难事，找到com.thoughtworks.selenium.Selenium，添加方法:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> doCommand(String commmand, String<img src="http://www.blogjava.net/images/dot.gif" /> parameters);</span>
		</div>
		<p>然后在com.thoughtworks.selenium.DefaultSelenium中添加实现:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<span style="COLOR: #008080">1</span>
				<img id="Codehighlighter1_61_241_Open_Image" onclick="this.style.display='none'; Codehighlighter1_61_241_Open_Text.style.display='none'; Codehighlighter1_61_241_Closed_Image.style.display='inline'; Codehighlighter1_61_241_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top" />
				<img id="Codehighlighter1_61_241_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_61_241_Closed_Text.style.display='none'; Codehighlighter1_61_241_Open_Image.style.display='inline'; Codehighlighter1_61_241_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top" />
				<span style="COLOR: #0000ff">public</span>
				<span style="COLOR: #000000"> </span>
				<span style="COLOR: #0000ff">void</span>
				<span style="COLOR: #000000"> doCommand(String commmand, String<img src="http://www.blogjava.net/images/dot.gif" /> parameters) </span>
				<span id="Codehighlighter1_61_241_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
						<img src="http://www.blogjava.net/images/dot.gif" />
				</span>
				<span id="Codehighlighter1_61_241_Open_Text">
						<span style="COLOR: #000000">{<br /></span>
						<span style="COLOR: #008080">2</span>
						<span style="COLOR: #000000">
								<img id="Codehighlighter1_95_104_Open_Image" onclick="this.style.display='none'; Codehighlighter1_95_104_Open_Text.style.display='none'; Codehighlighter1_95_104_Closed_Image.style.display='inline'; Codehighlighter1_95_104_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top" />
								<img id="Codehighlighter1_95_104_Closed_Image" style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_95_104_Closed_Text.style.display='none'; Codehighlighter1_95_104_Open_Image.style.display='inline'; Codehighlighter1_95_104_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top" />   String[] paras </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #0000ff">new</span>
						<span style="COLOR: #000000"> String[]</span>
						<span id="Codehighlighter1_95_104_Closed_Text" style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff">
								<img src="http://www.blogjava.net/images/dot.gif" />
						</span>
						<span id="Codehighlighter1_95_104_Open_Text">
								<span style="COLOR: #000000">{</span>
								<span style="COLOR: #000000">""</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #000000">""</span>
								<span style="COLOR: #000000">,</span>
								<span style="COLOR: #000000">""</span>
								<span style="COLOR: #000000">}</span>
						</span>
						<span style="COLOR: #000000">
								<br />
						</span>
						<span style="COLOR: #008080">3</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />   </span>
						<span style="COLOR: #0000ff">for</span>
						<span style="COLOR: #000000"> (</span>
						<span style="COLOR: #0000ff">int</span>
						<span style="COLOR: #000000"> i </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">0</span>
						<span style="COLOR: #000000">; i </span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000"> parameters.length </span>
						<span style="COLOR: #000000">&amp;&amp;</span>
						<span style="COLOR: #000000"> i </span>
						<span style="COLOR: #000000">&lt;</span>
						<span style="COLOR: #000000"> </span>
						<span style="COLOR: #000000">3</span>
						<span style="COLOR: #000000">; i</span>
						<span style="COLOR: #000000">++</span>
						<span style="COLOR: #000000">)<br /></span>
						<span style="COLOR: #008080">4</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />      paras[i] </span>
						<span style="COLOR: #000000">=</span>
						<span style="COLOR: #000000"> parameters[i];<br /></span>
						<span style="COLOR: #008080">5</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top" />   commandProcessor.doCommand(command, paras);<br /></span>
						<span style="COLOR: #008080">6</span>
						<span style="COLOR: #000000">
								<img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top" />}</span>
				</span>
		</div>
		<p>然后试验一下:</p>
		<div style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee">
				<img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top" />
				<span style="COLOR: #000000">selenium.doCommand(</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">clickAndWait</span>
				<span style="COLOR: #000000">"</span>
				<span style="COLOR: #000000">);</span>
		</div>
		<p>在我们使用纯RC mode之前曾经用过一段中间方案，将rc code转化为fit code来跑(因为rc不支持https)，由于不是真正的rc mode，像isTextPresent之类的方法都没有办法使用，只能使用FIT mode command。因此如果因为一些特殊的原因(https, chrome起不来，hta bug多等等)，你没有办法使用RC mode，但是有希望得到RC可重构的好处，那么这个tricky的技巧倒是不错的选择。</p>
		<p>5. Using chrome and IE hta lanucher to support https<br />6. Run test using different browser lanucher to test browser compatibility</p>
		<p>这两个都是和browser lanucher相关的，Selenium和JWebUnit最大的不同在于它使用真实的浏览器来跑测试，从而可以更加真实地考察系统在不同浏览器中的表现。因此使用不同的浏览器lanucher来运行测试，可以更好测试应用的浏览器兼容性，这对于web 2.0应用而言是很有帮助的。此外，使用rc提供的试验性lanucher，chrome和hta可以解决跨domain测试和https的问题。不过目前hta还是有很多bug的，推荐使用chrome。当然，最希望的还是澳洲的同事可以早日在selenium里提供https支持。<br /></p>
<img src ="http://www.blogjava.net/raimundox/aggbug/61860.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-08-04 21:59 <a href="http://www.blogjava.net/raimundox/archive/2006/08/04/61860.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>ANTLR Lexer Tips</title><link>http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Mon, 27 Mar 2006 06:44:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/37605.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html#Feedback</comments><slash:comments>4</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/37605.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/37605.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 参加ThoughtWorks University的一个来月没啥事情，闲了写写compiler玩。发现Lexer部分比较基础也比较常用，有很多相似的东西，每次都要写一遍也太麻烦了，下面是我按着JSL写的一个common java-like lexer，对于大多数接近java语法的语言估计是够用了。BTW：这个Lexer定义是TDD出来，以通过测试为要务，可能可读性不太强。1.WhiteSpaceC...&nbsp;&nbsp;<a href='http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html'>阅读全文</a><img src ="http://www.blogjava.net/raimundox/aggbug/37605.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-03-27 14:44 <a href="http://www.blogjava.net/raimundox/archive/2006/03/27/37605.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A Patch for Ruby Watir Test Framework</title><link>http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Wed, 11 Jan 2006 03:30:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/27549.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/27549.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/27549.html</trackback:ping><description><![CDATA[昨天发现了Ruby Watir里的一个小问题，没有办法在Text Field里输入中文。虽然已经hack了，但是还是不太爽，G.H.Hardy说：<br><br>Beauty is the first 
test: there is no permanent place in this world for ugly mathematics. <br><br>感动了我好久。现在换个说法：<br><br>Beauty is the first 
test: there is no permanent place in this world for ugly hack code. <br><br>这个问题也不太难出理，ruby作为C的front interface在字符串处理上有很深的C的痕迹，嗯，10年前我还是个C程序员嘛，按照从前的做法区分ASCII码。<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, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 0);">def characters_in(value)&nbsp;<br></span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;value.length&nbsp;<br></span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;len&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;value[index]&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">128</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;:&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">5</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;yield&nbsp;value[index,&nbsp;len]<br></span><span style="color: rgb(0, 128, 128);">6</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);">&nbsp;len<br></span><span style="color: rgb(0, 128, 128);">7</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;end&nbsp;<br></span><span style="color: rgb(0, 128, 128);">8</span>&nbsp;<span style="color: rgb(0, 0, 0);">end</span></div><br>把TextField里的doKeyPress改一下：<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, 128, 128);">1</span>&nbsp;<span style="color: rgb(0, 0, 0);">characters_in(value)&nbsp;{</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">c</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">&nbsp;<br></span><span style="color: rgb(0, 128, 128);">2</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;sleep&nbsp;@ieController.typingspeed<br></span><span style="color: rgb(0, 128, 128);">3</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;@o.value&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;@o.value.to_s&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;c<br></span><span style="color: rgb(0, 128, 128);">4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;fire_key_events}</span></div><br>搞定！但是还是很丑，直接把别人的code改了，contributing to eclipse里说要contribute不要随便change别人的代码。好吧，好在ruby扩展起来也不难：<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, 128, 128);">&nbsp;1</span>&nbsp;<span style="color: rgb(0, 0, 0);">require&nbsp;</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">Watir</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">&nbsp;2</span>&nbsp;<span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">&nbsp;3</span>&nbsp;<span style="color: rgb(0, 0, 0);">module&nbsp;Watir<br></span><span style="color: rgb(0, 128, 128);">&nbsp;4</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;module&nbsp;Cn<br></span><span style="color: rgb(0, 128, 128);">&nbsp;5</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;IE&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">Watir::IE<br></span><span style="color: rgb(0, 128, 128);">&nbsp;6</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;text_field(how&nbsp;,&nbsp;what</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">nil)<br></span><span style="color: rgb(0, 128, 128);">&nbsp;7</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">&nbsp;TextField.</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">(self,&nbsp;how,&nbsp;what)<br></span><span style="color: rgb(0, 128, 128);">&nbsp;8</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">&nbsp;9</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">10</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">11</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;TextField&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;Watir::TextField<br></span><span style="color: rgb(0, 128, 128);">12</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;doKeyPress(&nbsp;value&nbsp;)<br></span><span style="color: rgb(0, 128, 128);">13</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;begin<br></span><span style="color: rgb(0, 128, 128);">14</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxLength&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;@o.maxLength<br></span><span style="color: rgb(0, 128, 128);">15</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;value.length&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;maxLength<br></span><span style="color: rgb(0, 128, 128);">16</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;value&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;suppliedValue[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">&nbsp;..&nbsp;maxLength&nbsp;]<br></span><span style="color: rgb(0, 128, 128);">17</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@ieController.log&nbsp;</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">&nbsp;Supplied&nbsp;string&nbsp;is&nbsp;#{suppliedValue.length}&nbsp;chars,&nbsp;which&nbsp;exceeds&nbsp;the&nbsp;max&nbsp;length&nbsp;(#{maxLength})&nbsp;of&nbsp;the&nbsp;field.&nbsp;Using&nbsp;value:&nbsp;#{value}</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">18</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">19</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;rescue<br></span><span style="color: rgb(0, 128, 128);">20</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;#&nbsp;probably&nbsp;a&nbsp;text&nbsp;area&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">&nbsp;so&nbsp;it&nbsp;doesnt&nbsp;have&nbsp;a&nbsp;max&nbsp;Length<br></span><span style="color: rgb(0, 128, 128);">21</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;maxLength&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">22</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">23</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">24</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Cn.characters_in(value)&nbsp;{</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">c</span><span style="color: rgb(0, 0, 0);">|</span><span style="color: rgb(0, 0, 0);">&nbsp;<br></span><span style="color: rgb(0, 128, 128);">25</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;sleep&nbsp;@ieController.typingspeed<br></span><span style="color: rgb(0, 128, 128);">26</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;@o.value&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;@o.value.to_s&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;c<br></span><span style="color: rgb(0, 128, 128);">27</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;fire_key_events}<br></span><span style="color: rgb(0, 128, 128);">28</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">29</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">30</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">31</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;def&nbsp;Cn.characters_in(value)&nbsp;<br></span><span style="color: rgb(0, 128, 128);">32</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">33</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);">&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">&nbsp;value.length&nbsp;<br></span><span style="color: rgb(0, 128, 128);">34</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;len&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;value[index]&nbsp;</span><span style="color: rgb(0, 0, 0);">&gt;</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">128</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">2</span><span style="color: rgb(0, 0, 0);">&nbsp;:&nbsp;</span><span style="color: rgb(0, 0, 0);">1</span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">35</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;yield&nbsp;value[index,&nbsp;len]<br></span><span style="color: rgb(0, 128, 128);">36</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;index&nbsp;</span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);">&nbsp;len<br></span><span style="color: rgb(0, 128, 128);">37</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;end&nbsp;<br></span><span style="color: rgb(0, 128, 128);">38</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">39</span>&nbsp;<span style="color: rgb(0, 0, 0);">&nbsp;&nbsp;end<br></span><span style="color: rgb(0, 128, 128);">40</span>&nbsp;<span style="color: rgb(0, 0, 0);">end</span></div><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, 0);">require&nbsp;</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">watir-cn</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);"><br><br>ie&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;Watir::Cn::IE.start(</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">http://www.google.com</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">)<br>ie.text_field(:name,&nbsp;</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">q</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">).set(</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">Ruby&nbsp;Watir&nbsp;功能测试</span><span style="color: rgb(0, 0, 0);">'</span></div><br>成功。最后一步是贡献社区，直接登到rubyforge，找到Watir然后submit了两个patch：一个直接修改watir库的一个是独立的watir-cn的。推荐大家使用第二个的patch。地址在：<a href="http://rubyforge.org/tracker/index.php?func=detail&amp;aid=3232&amp;group_id=104&amp;atid=489">http://rubyforge.org/tracker/index.php?func=detail&amp;aid=3232&amp;group_id=104&amp;atid=489</a></span><br><img src ="http://www.blogjava.net/raimundox/aggbug/27549.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-01-11 11:30 <a href="http://www.blogjava.net/raimundox/archive/2006/01/11/27549.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A Day of Two Pragmatic Programmers'  Life</title><link>http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 10 Jan 2006 13:30:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/27469.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/27469.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/27469.html</trackback:ping><description><![CDATA[今天我和WPC被迫派给了一个很nonsense的活，客户给了我们两份名单，让我们对照我们SSO中的用户数据做一下数据维护，如果有的用户在SSO中没有就加进来；要是SSO中有，看一下OA里有没有，如果OA里没有写一个列表让OA的同志们去维护数据。本来是一个很枯燥的活，好在WPC和我都是pragmatic programers，于是生活变得有乐趣多了。<BR>解决这个问题最直接的做法，就是login到SSO平台上，然后一个用户一个用户的search，search完了再用OA Admin登陆查OA帐户。我们是pragmatic programmer嘛，这么繁琐的活动自然写程序搞定它。自然浮现两个选择：Ruby Watri，还有就是产自俺们公司的Selenium Script。<BR>上来先用Ruby Watri，这个东西好啊，简单啊。WPC找了一个以前写的example, 我照着改了一个用户的search，然后扩展：
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">#&nbsp;login&nbsp;in&nbsp;as&nbsp;sso&nbsp;admin<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;Watir::IE.start(sso_login_url)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">username</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).set(sso_admin_user)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">password</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).set(sso_admin_pass)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.button(:value,&nbsp;</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)">).click<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">#&nbsp;search&nbsp;user<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;Watir::IE.start(sso_search_url)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;9</SPAN> <SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">userName).set('张三')</SPAN><SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">10</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,0)">ie.button(:value,&nbsp;</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)">).click</SPAN></DIV><BR>跑到command line run一把，ruby login.rb，然后一个古怪的事情出现了<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">userName).set('张三')</SPAN></DIV>userName输入框highlight了一下，然后没有字...难道是编码问题？换了encoding重新save了一把，结果一样。郁闷...于是我和WPC想法是...Ruby中文有问题，不管了时间紧迫，换Selenium Test，自家的东西嘛。但是Selenium的Script是HTML-based的，写起来太麻烦。我们是pragmatic programmer嘛，这么繁琐的活动自然写程序搞定它。于是我来搞一个ScriptGenerator，WPC同志搞script template。一搞template WPC同志就比较兴奋，大喊:velocity！ velocity！哎，我机器上没有velocity的library，于是我决定pragmatic一把，直接writer output。找了一个Selenume Script Demo，在每行前面加上aaaa,每行末尾加上bbb，然后ctrl + f,aaa-&gt;writer.write(" bbb-&gt;"); 改几个"，introduce parameter, extract method, compose method飞快地重构之，一个hard code的generator引擎诞生了。WPC还在调template，我看了一下代码，蛮ugly的，refactory之：<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">private</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">static</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;String&nbsp;scriptTemplate;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">public</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">static</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">void</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;readScriptTemplate(String&nbsp;templateName)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;BufferedReader&nbsp;reader&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;BufferedReader(</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;FileReader(templateName));<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;String&nbsp;line&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;StringBuffer&nbsp;template&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;StringBuffer();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;9</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">while</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;((line&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;reader.readLine())&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">10</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;template.append(line).append(</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></SPAN><SPAN style="COLOR: rgb(0,128,128)">11</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;scriptTemplate&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;template.toString();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">12</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">13</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">14</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">finally</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">15</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">if</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(reader&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">16</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">17</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;reader.close();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">18</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">19</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">20</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">21</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">22</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">23</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">public</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">static</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">void</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;generatedScriptForUser(String&nbsp;path,&nbsp;String&nbsp;name)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">24</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Writer&nbsp;writer&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">25</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">26</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;BufferedWriter(</SPAN><SPAN style="COLOR: rgb(0,0,255)">new</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;FileWriter(path&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</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)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;name<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">27</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">.html</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">));<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">28</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.write(scriptTemplate<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">29</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;.replaceAll(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">\\$\\$userName\\$\\$</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">,&nbsp;name));<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">30</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">31</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;e.printStackTrace();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">32</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">finally</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">33</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">if</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(writer&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">null</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">34</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">try</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">35</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;writer.close();<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">36</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,255)">catch</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;(IOException&nbsp;e)&nbsp;{<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">37</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">38</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">39</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">40</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></DIV><BR>一下子少了无数代码，爽多了。然后wpc也搞好了template，按模版文件一generating，几十个selenium test script就出现了。嗯，write program that write program，有够pragmatic。<BR><BR>写了一个Test Suite，放到改一下Selenium Runner下跑一下又傻眼了。Selenium做的Functional Test，一般假定和被测的应用在一个URL base里，因此这样local“测”remoting就不太好，而且我们又是一个安全平台，URL base做安全基准的。一下就所有测试就crackdown在这里了。郁闷啊...<BR>Selenium文档，发现可以用driver来adpater local和remoting的环境，问题是这个drvier要自己写...郁闷...<BR>WPC在firefox上装了一个Selenium Recorder的plug in可以记录web page actions，然后replay。他发现这个东西能绕过Selenium的限制，于是决定看看他怎么实现的，找到code一看...原来是把selenium runner hack了...用javascript把url base生生的给改了...WPC说好啊，我们写一个Firefox Selenium Recorder Plugin的plug in吧，让他从一个目录里自动load script...然后WPC开始玩firefox plugin.<BR><BR>我决得我还是看看Ruby的中文支持吧，找来找去都没有说Ruby的中文有问题的，后来发现一个老大测了一下Ruby的中文字符串，说没问题。我忘了这个老大的URL了找到再补上。代码上看起来似乎也没什么问题。于是我怀疑是Watri的问题，看Watri的代码，发现Watri的设计思路就是为了模拟人的录入，然后找到这样的代码：<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,0,0)">def&nbsp;doKeyPress(value)<BR><BR><IMG src="http://www.blogjava.net/images/dot.gif"><BR><BR></SPAN><SPAN style="COLOR: rgb(0,0,255)">for</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;in&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">0</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;..&nbsp;value.length</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;<BR>&nbsp;&nbsp; sleep&nbsp;@ieController.typingspeed&nbsp;&nbsp;&nbsp;#&nbsp;typing&nbsp;speed<BR>&nbsp;&nbsp; c&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;value[i,</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">]<BR>&nbsp;&nbsp; #@ieController.log&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;adding&nbsp;c.chr&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;#.chr.to_s<BR>&nbsp;&nbsp; @o.value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;@o.value.to_s&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;&nbsp;#c.chr<BR>&nbsp;&nbsp; fire_key_events<BR>end<BR><BR><IMG src="http://www.blogjava.net/images/dot.gif"><BR><BR>end</SPAN></DIV>根据设定的延时模拟人敲击键盘。每一个间隔用String slice来输入。于是我试验了一下ruby的中文字符串切片：<BR><BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</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></SPAN><SPAN style="COLOR: rgb(0,128,128)">2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,255)">for</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;in&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">0</SPAN><SPAN style="COLOR: rgb(0,0,0)">..value.length</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;puts&nbsp;value[i,</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">]<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">end</SPAN></DIV>Ruby果然瞎菜了...value.length是4，每一个切片都是空...啊~~~~天啊，8bit char...C的时代啊。找到了问题就好办了，我权衡了fix watri unicode和直接hack它，最后我选择直接hack它，方法简单：<BR><BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">&nbsp;1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,255)">if</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;@ieController.typingspeed&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">!=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; </SPAN><SPAN style="COLOR: rgb(0,0,255)">for</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;i&nbsp;in&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">0</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;..&nbsp;value.length</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; sleep&nbsp;@ieController.typingspeed&nbsp;&nbsp;&nbsp;#&nbsp;typing&nbsp;speed<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; c&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;value[i,</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)">]<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; #@ieController.log&nbsp;&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;adding&nbsp;c.chr&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;#.chr.to_s<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;6</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; @o.value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;@o.value.to_s&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">+</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;c&nbsp;&nbsp;&nbsp;#c.chr<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;7</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; fire_key_events<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;8</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; end<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">&nbsp;9</SPAN> <SPAN style="COLOR: rgb(0,0,0)"></SPAN><SPAN style="COLOR: rgb(0,0,255)">else</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">10</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; @o.value&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;value<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">11</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">&nbsp; fire_key_events<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">12</SPAN> <SPAN style="COLOR: rgb(0,0,0)">end</SPAN></DIV><BR>然后测试一下：<BR>
<DIV style="BORDER-RIGHT: rgb(204,204,204) 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: rgb(204,204,204) 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: rgb(204,204,204) 1px solid; WIDTH: 98%; PADDING-TOP: 4px; BORDER-BOTTOM: rgb(204,204,204) 1px solid; BACKGROUND-COLOR: rgb(238,238,238)"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><SPAN style="COLOR: rgb(0,128,128)">1</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">require&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">'</SPAN><SPAN style="COLOR: rgb(0,0,0)">Watir</SPAN><SPAN style="COLOR: rgb(0,0,0)">'</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">2</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">3</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;Watir::IE.start(</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">http://www.google.com</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">)<BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">4</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.typingspeed&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">=</SPAN><SPAN style="COLOR: rgb(0,0,0)">&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">-</SPAN><SPAN style="COLOR: rgb(0,0,0)">1</SPAN><SPAN style="COLOR: rgb(0,0,0)"><BR></SPAN><SPAN style="COLOR: rgb(0,128,128)">5</SPAN>&nbsp;<SPAN style="COLOR: rgb(0,0,0)">ie.text_field(:name,&nbsp;</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">q</SPAN><SPAN style="COLOR: rgb(0,0,0)">"</SPAN><SPAN style="COLOR: rgb(0,0,0)">).set(</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></DIV><BR>搞定。于是准备改Ruby脚本，这个时候客户下班了，我们决定明天继续，一共用时2小时...<BR><BR>最后说一下需求，一共有多少数据呢？70条...如果pair录入的话，大约40-50分钟吧<BR><BR>结论:<BR><BR>1.Pragmatic Programmer都是很懒的，重复5次的工作都回用代码来写。<BR>2.Pragmatic Programmer都是很有好奇心的，太多的重复性劳动只能分散他们的注意力，不知道会搞出什么了，我估计我要没有hack Watri，WPC已经开始写Firefox plugin了。<BR>3.Pragmatic Programmer都是“古程序员”，写程序操纵计算机是很有乐趣的。<BR>4.比一个Pragmatic Programmer更能折腾的是两个Pragmatic Programmer...<BR><BR><BR><img src ="http://www.blogjava.net/raimundox/aggbug/27469.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2006-01-10 21:30 <a href="http://www.blogjava.net/raimundox/archive/2006/01/10/27469.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>丧钟为谁鸣?(4)</title><link>http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Wed, 21 Dec 2005 07:51:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/24957.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/24957.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/24957.html</trackback:ping><description><![CDATA[<P>第3. 一切皆对象和面向对象的理论基础</P>
<P>老庄是反对一切皆对象的，而TrustNo1在javaeye的一篇帖子上说:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">第一，我可以很负责的说,OO的，70年代成型，80年代在理论基础上就给人毙掉。从这种意义上说不是OO死不死的问题，而是OO还活着么？当然理论基础给人毙掉，不是说没有用。</SPAN></DIV>
<P>我先说面向对象的理论基础的问题，至于一切皆对象稍后再表。<BR><BR>所谓面向对象的理论基础其实是没有的，原因很简单，面向对象根本就不是一种计算模型。在第一次软件危机的那个时代，对与计算机的非数值计算应用的讨论以及对于可计算性问题的研究和发展，大抵确立了几种主流的计算模型：递归函数类，图灵机，Lambda演算，Horn子句，Post系统等等。<BR><BR>其中递归函数类是可计算性问题的数学解释;图灵机是图灵解决可计算问题的时候所设计的装置，其后成为计算机的装置模型，与图灵机相关的形式语言和自动机成为了命令式语言的理论基础;lambda演算成为了函数式语言的理论基础;Horn子句是prolog这类逻辑语言的理论基础。但是我们惊讶的发现，面向对象没有计算模型的理论基础，换而言之，面向对象根本就不是从可计算性的研究上发展过来的，那么面向对象的理论基础的价值本身就不大。</P>
<P>所以我很奇怪的一个问题就是TrustNo1所谓的面向对象在80年代理论基础上给人毙掉的说法是从何而来的？既然面向对象本质上不是一种计算模型，那么它大抵上只能归结为一种应用技术，应用技术自然可以从各种不同的领域里得到相似的应用，那么毙掉的理论基础所指的又是什么呢？甚怪之。</P>
<P>既然面向对象不是一个计算模型，那么我们可以从不同的角度推断出OO的各种形态，老庄已经出给了从ADT引出OO的问题以及例子，我就不罗嗦了，我给一个从Functional Programming出来的例子，其实就是SICP里的Data as Procedure。</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;(make</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">user&nbsp;name&nbsp;age&nbsp;sex)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;(define&nbsp;(dispatch&nbsp;message)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getName)&nbsp;name)</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getAge)&nbsp;age)</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getSex)&nbsp;sex))</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">&nbsp;(error&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">messageNotUnderstand))))</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;dispatch)</SPAN></DIV>
<P>然后我们就可以</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;vincent&nbsp;(make</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">user&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">Vincent&nbsp;24&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">Male))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(vincent&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getName)</SPAN></DIV>
<P>自然的，如果我调用</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(vincent&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">sayHi)</SPAN></DIV>
<P>会得到一个messageNotUnderstand的runtime错误，这就是一个很自然dyanmic type的对象封装，最早的面向对象系统Smalltalk和CLOS基本上都是这个路子，于是有一个问题，为什么最早的面向对象系统都是dyanmic type？这里就跟lambda演算有关了。</P>
<P>lambda演算这个计算模型根本的一个假设就是，对于任何一个定义良好的数学函数，我都可以使用lambda抽象来表述他的求值，因此无论是什么东西你能够构造lambda抽象的话，我就能计算。这个地方东西很多，大家可以找找lambda演算相关的资料，这里我说三件事(由于lambda太难输入，我用scheme程序代替，然后由于alpha变化，beta规约和eta规约我也用scheme伪码来模拟。)</P>
<P>第一个是数值的表述，其实这个很简单，不考虑丘奇代数的系统的话，我们可以把数值表示成单值函数:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;one&nbsp;(lambda&nbsp;(x)&nbsp;</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">))</SPAN></DIV>
<P>这个东西无论给什么x都返回1，然后根据lambda演算里的alpha变换，这个lambda抽象等价于数值1。因此，对于所有的数值，我们可以按lambda演算处理。</P>
<P>第二个是bool的表达，也就是如何逻辑进行lambda抽象，下面我直接给出了，缺省认为大家都看了SICP，对Scheme也颇有心得。</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;(lambda&nbsp;(x&nbsp;y)&nbsp;x))&nbsp;;;;这个函数也叫select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">first<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;(lambda&nbsp;(x&nbsp;y)&nbsp;x));;;这个函数也叫select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">second<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;(lambda&nbsp;(conditon&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">)&nbsp;(condition&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">)))</SPAN></DIV>
<P>然后我就可以做一个测试</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">true</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(</SPAN><SPAN style="COLOR: #0000ff">if</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">false</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">4</SPAN></DIV>
<P>因此，对于所有bool我们可以按lambda演算来处理</P>
<P>第三个是自定义类型，这里我们还是先看一个Lisp里的例子，序对。</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;(cons&nbsp;a&nbsp;b)&nbsp;(lambda&nbsp;(dispath)&nbsp;(dispatch&nbsp;a&nbsp;b)))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;(car&nbsp;list)&nbsp;(list&nbsp;select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">first))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;(cdr&nbsp;list)&nbsp;(list&nbsp;select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">second))</SPAN></DIV>
<P>这里依旧是high-order，我们来测试<BR></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;list1&nbsp;(cons&nbsp;</SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">2</SPAN><SPAN style="COLOR: #000000">))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(car&nbsp;list1)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(cdr&nbsp;list1)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">2</SPAN></DIV>
<P>这里大家自己用beta规约算一下，就发现的确是这样的。这里我们又可以看到，在lambda演算里，根本没有数据或者类型。有的永远各种各样的lambda抽象而已(目前已经有了带类型的lambda演算)。这里说一句题外话，SICP里的Data as Procedure其实就是在说这个问题，不过他没明说，而是用了一种特殊的用法而引出了消息传递风格，我觉得这里SICP有些顾此失彼，对于data as procedure我总结的一般形式是</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;(construct</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">function&nbsp;value1&nbsp;value2&nbsp;value3&nbsp;value4<IMG src="http://www.blogjava.net/images/dot.gif">valuen)&nbsp;(lambda&nbsp;(dispatch)&nbsp;(dispatch&nbsp;value1&nbsp;value2&nbsp;value3&nbsp;value4<IMG src="http://www.blogjava.net/images/dot.gif">valuen)))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;(select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">function1&nbsp;data)&nbsp;(data&nbsp;select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">first))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;(select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">function2&nbsp;data)&nbsp;(data&nbsp;select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">second))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><IMG src="http://www.blogjava.net/images/dot.gif">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;(select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">functionn&nbsp;data)&nbsp;(data&nbsp;select</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">last))</SPAN></DIV>
<P>综上所述，我们看到在lambda演算里，一切都是lambda抽象，然后对于不同的lambda抽象使用alpha变换，beta规约和eta规约，表述各种不同计算。看，在面向对象之前就已经有了一切皆某某的完美的计算理论存在了。而且回顾一下：</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">(define&nbsp;(make</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">user&nbsp;name&nbsp;age&nbsp;sex)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;(define&nbsp;(dispatch&nbsp;message)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(cond&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getName)&nbsp;name)</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getAge)&nbsp;age)</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;((eq</SPAN><SPAN style="COLOR: #000000">?</SPAN><SPAN style="COLOR: #000000">&nbsp;message&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getSex)&nbsp;sex))</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</SPAN><SPAN style="COLOR: #0000ff">else</SPAN><SPAN style="COLOR: #000000">&nbsp;(error&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">messageNotUnderstand))))</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">&nbsp;&nbsp;dispatch)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(define&nbsp;vincent&nbsp;(make</SPAN><SPAN style="COLOR: #000000">-</SPAN><SPAN style="COLOR: #000000">user&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">Vincent&nbsp;24&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">Male))<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>(vincent&nbsp;</SPAN><SPAN style="COLOR: #000000">'</SPAN><SPAN style="COLOR: #000000">getName)</SPAN></DIV>
<P>我们有理由说，对象其实就是一个lambda抽象，所以一切皆对象不过是一切皆lambda抽象的演化，这也是为什么SICP里把面向对象称作一种“方便的界面”而不是一种抽象的方法的原因了。那么对象和lambda抽象又什么区别呢？<BR><BR>嘿嘿，熟悉FP的人都应该知道了，就是Side-Effect，副作用。对象允许对其内部状态进行修改，那么这个东西就破化了eta规约的前提条件，也就是说允许修改内部状态的东西，已经不是一个可以进行lambda计算的lambda抽象了。因此暂且给一个别的名字吧，就叫对象吧.....因此我认为，对象很大程度上是一种带有副作用的lambda抽象。</P>
<P>我在有一篇blog上写了Say sorry to object-oriented，里面给了一只用对象作分支的例子，这里就不重复了，有兴趣大家可以去看一下（刚才好像在JavaEye上看到一个说法，说Everything is Object是Smalltalk的广告语，唉，Smalltalk里的的的确确everything is object啊。）<BR><BR>这里我们来总结一下，面向对象作为一种“方便的界面”主要解决了一个局部化和模块化的问题，这是从lambda演算和函数编程的角度来看面向对象技术。（taowen在他的一篇blog上说，面向对象局部化了Side-Effect，我深以为然），这个东西我个人认为更加接近面向对象本来的意思，而不是由ADT里发展出来的带类型的对象系统的那个意思。因此老庄不以为然的面向对象类型系统，我也不以为然。但是面向对象作为lambda抽象的界面，我觉得还是很不错的。这一点在Smalltalk和Ruby里都有不错的体现。</P><img src ="http://www.blogjava.net/raimundox/aggbug/24957.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-21 15:51 <a href="http://www.blogjava.net/raimundox/archive/2005/12/21/24957.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>丧钟为谁鸣？(3)</title><link>http://www.blogjava.net/raimundox/archive/2005/12/21/24891.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 20 Dec 2005 16:44:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/21/24891.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/24891.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/21/24891.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/24891.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/24891.html</trackback:ping><description><![CDATA[<P>第2 继承</P>
<P>前面已经说过了，继承至少有2个语义: 实现继承和类型继承，在说明这两个东西之前，我们继续来看上面的例子</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">Person</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playSoloOnInstrument:instrument<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;instrument&nbsp;playNote:&nbsp;Note&nbsp;C;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playNote:&nbsp;Note&nbsp;D;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playNote:&nbsp;Note&nbsp;E.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Person</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playBackgroundOnInstrument:instrument<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;instrument&nbsp;playChord:&nbsp;Chord&nbsp;C1;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playChord:&nbsp;Chord&nbsp;C1;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playChord:&nbsp;Chord&nbsp;C1;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Person</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playBWV996OnInstrument:instrument<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;instrument&nbsp;playNote:&nbsp;Note&nbsp;C;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playChord:&nbsp;Chord&nbsp;C;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playNote:&nbsp;Note&nbsp;D.</SPAN></DIV>
<P>现在我们看playBWV996这个消息，BWV996是Bach所写一个鲁特琴组曲，鲁特琴是弹拨乐器，同时也是和声乐器(所谓和声乐器就是可以演奏和声)。在很多乐器上都有改编的版本，比如鲁特琴的近亲吉他等等，这个时候，我们可以实现这样几个类</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">Lute</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playNote:note<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Lute</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playChord:note<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Guitar</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playNote:note<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Guitar</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playChord:note<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Bass</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playNote:note<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"></SPAN></DIV>
<P>然后我们可以尝试以此调用</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">vincent.playBWV996OnInstrument:&nbsp;Guitar&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent.playBWV996OnInstrument:&nbsp;Lute&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent.playBWV996OnInstrument:&nbsp;Bass&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">.</SPAN></DIV>
<P>最后一个会得到一个messageNotUnderstand的错误。也就是说，对于Bass而言由于不能演奏和声从而不能演奏BMV996(不过这个世界上能人太多了...哎)，我们换到静态类型面向对象系统来看。<BR>对于第一个方法，playSolo的时候我们要求的类型是能够演奏单音的。我们可以写出来</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_25_68_Open_Image onclick="this.style.display='none'; Codehighlighter1_25_68_Open_Text.style.display='none'; Codehighlighter1_25_68_Closed_Image.style.display='inline'; Codehighlighter1_25_68_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_25_68_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_25_68_Closed_Text.style.display='none'; Codehighlighter1_25_68_Open_Image.style.display='inline'; Codehighlighter1_25_68_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;SoloInstrument&nbsp;</SPAN><SPAN id=Codehighlighter1_25_68_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_25_68_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;SoloInstrument&nbsp;playNote(Note&nbsp;note);&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>对于第二个方法，playChord的时候我们要求的类型是能够演奏和弦的，我们可以写出来</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_26_72_Open_Image onclick="this.style.display='none'; Codehighlighter1_26_72_Open_Text.style.display='none'; Codehighlighter1_26_72_Closed_Image.style.display='inline'; Codehighlighter1_26_72_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_26_72_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_26_72_Closed_Text.style.display='none'; Codehighlighter1_26_72_Open_Image.style.display='inline'; Codehighlighter1_26_72_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;ChordInstrument&nbsp;</SPAN><SPAN id=Codehighlighter1_26_72_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_26_72_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;ChordInstrument&nbsp;playChord(Chord&nbsp;note);&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>而对于第三个方法，playBWV996的时候我们要求既能演奏和弦也能演奏单音，这个时候出现一个问题，我们怎么处理Instrument的继承关系?一个能演奏和弦的乐器是否可以演奏单音(答案是一般而言是的，但是也不排除有一些不是这样的)?还是我们简单的写:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_72_74_Open_Image onclick="this.style.display='none'; Codehighlighter1_72_74_Open_Text.style.display='none'; Codehighlighter1_72_74_Closed_Image.style.display='inline'; Codehighlighter1_72_74_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_72_74_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_72_74_Closed_Text.style.display='none'; Codehighlighter1_72_74_Open_Image.style.display='inline'; Codehighlighter1_72_74_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;SoloAndChordInstrument&nbsp;</SPAN><SPAN style="COLOR: #0000ff">extends</SPAN><SPAN style="COLOR: #000000">&nbsp;SoloInstrument,&nbsp;ChordInstrument</SPAN><SPAN id=Codehighlighter1_72_74_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_72_74_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>或者</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_25_109_Open_Image onclick="this.style.display='none'; Codehighlighter1_25_109_Open_Text.style.display='none'; Codehighlighter1_25_109_Closed_Image.style.display='inline'; Codehighlighter1_25_109_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_25_109_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_25_109_Closed_Text.style.display='none'; Codehighlighter1_25_109_Open_Image.style.display='inline'; Codehighlighter1_25_109_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;BWV996Playable&nbsp;</SPAN><SPAN id=Codehighlighter1_25_109_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_25_109_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;BWV996Playable&nbsp;playNote(Note&nbsp;note);&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;BWV996Playable&nbsp;playChord(Chord&nbsp;note);&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>对于动态类型简单的隐性类型约定，显示的类型系统带来的一个副作用就是我们必须处理类型之间的关系。<STRONG>注意这里是类型之间的关系，而不是对象之间的关系</STRONG>。老庄同志批了很多篇的面向对象的抽象，面向对象的类型系统以及面向对象的本体论，<STRONG>其实都在是在类型关系上折腾，而不是在对象关系上折腾</STRONG>。而事实上面向对象的<STRONG>类型系统并非必然就是静态类型系统，而我们的类之间的关系不一定就和类型的关系相一致。</STRONG>就像上例所示，在Smalltalk里，Lute，Guitar和Bass之间没有任何的继承关系，但是对于person的3个消息而言，它们却是有类型的。<BR><BR>因此老庄所批的，是对象类型系统的抽象能力，而非面向对象的抽象能力。正如他在类型系统里所给的例子，那张他认为很失败的面向对象的图，其实可以完全不依赖继承来实现，而对这个类型系统的消费者而言，他们能够以一定的类型的观点，来处理这个系统的对象。</P>
<P>而老庄最后一个结论:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">我的结论是：“一个类型，是由其本质决定了所能表现出的可操作性，而不是有其所能接受的操作决定了其本质。然而，OO正好把这个问题搞反了！”</SPAN></DIV>
<P>我的看法是，这句话根本就是诡辩，前面半句的主语是“一个类型”，后面半句的主语是"OO"...<BR><BR>虽然前半句是对的，但是换一样说法可能更好:"<STRONG>所能接受的操作反映了其本质</STRONG>"，面向对象本身就没有说我要做一个本质抽象，这一点在Smalltalk的类型判断操作上的可能是一个佐证，Smalltalk用isKindOf来判断继承关系，我们来玩一个文字游戏，改成俚语就是kinda，也就是"有一点，有几分"的意思，而不是说，“就是”，或者“从分类学上可证明之类的含义”。我再举一个龌龊的例子。</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">vincent&nbsp;ballon:&nbsp;AirBallon&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent&nbsp;ballon:&nbsp;Condom&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">.</SPAN></DIV>
<P>气球和保险套，对于ballon这个方法而言是一个类型，都是"有几分"可以吹起来。但是我怎么定义一个精确的本质？Ballonable？还是MakeFromLatexAndVeryThin?或者简单说FlexableAndThin？</P>
<P>在继承这一点上，我想老庄引文中:Elminster的话是从事物的特征与属性归纳出它的“类型”。恰恰对于静态类型面向对象系统是可行的。如我前文所述，我把一个object和所有sender的约定（也就是interface），继承在一起，恰恰就是一个颇为恰当的类型定义。<BR><BR>而对于动态类型系统里的面向对象语言，继承的也有类型继承的含义，但是并不是唯一的途径。用一句我们常说的话，在静态类型系统里，类型和类是紧耦合的，动态类型系统中他们的耦合比较松。<BR><BR>从此而观，所有对于面向对象的哲学考虑以及本体的思考，对于动态面向对象系统已经不是那么迫切了。而把对象类型系统的不足归咎于面向对象的不足，也似乎论据不足。</P><img src ="http://www.blogjava.net/raimundox/aggbug/24891.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-21 00:44 <a href="http://www.blogjava.net/raimundox/archive/2005/12/21/24891.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>丧钟为谁鸣？(2)</title><link>http://www.blogjava.net/raimundox/archive/2005/12/21/24889.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 20 Dec 2005 16:22:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/21/24889.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/24889.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/21/24889.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/24889.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/24889.html</trackback:ping><description><![CDATA[<P>第1 关于"接口"</P>
<P>关于接口的问题老庄说对了，这个东西并不属于面向对象的概念，而且在动态类型面向对象语言(比如Ruby, Smalltalk里)，根本没有这个东西。这是一个纯粹的静态类型面向对象语言的特性，或者直接说，接口就是一个纯类型(Type)。还是上次的例子：</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN><IMG id=Codehighlighter1_21_84_Open_Image onclick="this.style.display='none'; Codehighlighter1_21_84_Open_Text.style.display='none'; Codehighlighter1_21_84_Closed_Image.style.display='inline'; Codehighlighter1_21_84_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_21_84_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_21_84_Closed_Text.style.display='none'; Codehighlighter1_21_84_Open_Image.style.display='inline'; Codehighlighter1_21_84_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_21_84_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_21_84_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playNote(Note&nbsp;note);<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playChord(Chord&nbsp;chord);<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>in&nbsp;Person&nbsp;Class<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_141_148_Open_Image onclick="this.style.display='none'; Codehighlighter1_141_148_Open_Text.style.display='none'; Codehighlighter1_141_148_Closed_Image.style.display='inline'; Codehighlighter1_141_148_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_141_148_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_141_148_Closed_Text.style.display='none'; Codehighlighter1_141_148_Open_Image.style.display='inline'; Codehighlighter1_141_148_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playSolo(Instrument&nbsp;instrument)&nbsp;</SPAN><SPAN id=Codehighlighter1_141_148_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_141_148_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR></SPAN><SPAN style="COLOR: #008080">10</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>在我接触Smalltalk的最开始的一段时间里，这种地方是让我最难受，我已经习惯了用类型辅助我的思维，但是我发现我在Smalltalk里做不到，虽然我可以写出</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">Instrument</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playNote:note<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #000000">^</SPAN><SPAN style="COLOR: #000000">self&nbsp;subclassResponsibility.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Instrument</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playChord:chord<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #000000">^</SPAN><SPAN style="COLOR: #000000">self&nbsp;subclassResponsibility.</SPAN></DIV>
<P>但是他却不是一个接口，我可以很用</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">instrument&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>instrument&nbsp;playNote:&nbsp;Note&nbsp;C.</SPAN></DIV>
<P>来构造一个Instrument之后在它之上调用playNote方法，然而我会得到一个messageNotUnderstand的错误，Smalltalk和Ruby里没有Abstract的概念。也就是说abstract method，abstract class以及interface，都不是面向对象的概念（或者严格一些说，都不是面向对象的必须的概念），而是面向对象类型系统的概念。那么在Smalltalk里我们会怎么做呢？</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">Person</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playSoloOnInstrument:instrument<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;instrument&nbsp;playNote:&nbsp;Note&nbsp;C;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playNote:&nbsp;Note&nbsp;D;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playNote:&nbsp;Note&nbsp;E.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Person</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playBackgroundOnInstrument:instrument<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;instrument&nbsp;playChord:&nbsp;Chord&nbsp;C1;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; playChord:&nbsp;Chord&nbsp;C1;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; playChord:&nbsp;Chord&nbsp;C1;</SPAN></DIV>
<P>对于playSoloOnInstrument:instrument，我们对于instrument的类型是有要求的，就是它必须能够接受playNote这个消息。当然这个类型需要是隐性，我也可以对等的写出静态面向对象的代码把这个隐性的类型显示的表示出来:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_21_60_Open_Image onclick="this.style.display='none'; Codehighlighter1_21_60_Open_Text.style.display='none'; Codehighlighter1_21_60_Closed_Image.style.display='inline'; Codehighlighter1_21_60_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_21_60_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_21_60_Closed_Text.style.display='none'; Codehighlighter1_21_60_Open_Image.style.display='inline'; Codehighlighter1_21_60_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_21_60_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_21_60_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;Instrument&nbsp;playNote(Note&nbsp;note);&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>同样对于第二个方法我们也可以写出来:</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_21_61_Open_Image onclick="this.style.display='none'; Codehighlighter1_21_61_Open_Text.style.display='none'; Codehighlighter1_21_61_Closed_Image.style.display='inline'; Codehighlighter1_21_61_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_21_61_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_21_61_Closed_Text.style.display='none'; Codehighlighter1_21_61_Open_Image.style.display='inline'; Codehighlighter1_21_61_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_21_61_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_21_61_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;Instrument&nbsp;playChord(Note&nbsp;note);&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>如果我们需要多于一个的消息也是一样的，比如</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">Person</SPAN><SPAN style="COLOR: #000000">&gt;&gt;</SPAN><SPAN style="COLOR: #000000">playBWV996OnInstrument:instrument<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;instrument&nbsp;playNote:&nbsp;Note&nbsp;C;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playChord:&nbsp;Chord&nbsp;C;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;playNote:&nbsp;Note&nbsp;D.</SPAN></DIV>
<P>同样这个时候隐性的类型需要就是</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_21_98_Open_Image onclick="this.style.display='none'; Codehighlighter1_21_98_Open_Text.style.display='none'; Codehighlighter1_21_98_Closed_Image.style.display='inline'; Codehighlighter1_21_98_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_21_98_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_21_98_Closed_Text.style.display='none'; Codehighlighter1_21_98_Open_Image.style.display='inline'; Codehighlighter1_21_98_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_21_98_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_21_98_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;Instrument&nbsp;playNote(Note&nbsp;note);&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;Instrument&nbsp;playChord(Note&nbsp;note);&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>那么接口是什么呢？我给出一个不确切的说法，<STRONG>interface是一个消息的发送者(sender)和一个消息的接受者(reciver)间的一种类型的约定</STRONG>，也就是说在我看来interface的用处主要在细粒度的显式类型约定。我有一个同事，每次写代码都为一个Test Case所要测试的对象定义一个interface，每个interface都只有2-3个方法（lx同学夸你呢:D），这是很得interface之三味的用法。这种的做法对于在静态的面向对象系统的好处我们在继承里再论述。</P>
<P>至于老庄所说的接口是多继承的一种代替品，这只不过是世俗的看法，在静态类型的面向对象里，继承至少有2个语义:</P>
<P>1.实现继承，这个在Smalltalk，Ruby，C++里有，而在java里没有，C++里是通过private extends来实现的</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_46_48_Open_Image onclick="this.style.display='none'; Codehighlighter1_46_48_Open_Text.style.display='none'; Codehighlighter1_46_48_Closed_Image.style.display='inline'; Codehighlighter1_46_48_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_46_48_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_46_48_Closed_Text.style.display='none'; Codehighlighter1_46_48_Open_Image.style.display='inline'; Codehighlighter1_46_48_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;SubClassA:&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;ImplementationParent&nbsp;</SPAN><SPAN id=Codehighlighter1_46_48_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_46_48_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>这也是C++里为数不多的subclass不是subtype的例子。</P>
<P>2.类型继承，这个在C++和java里有，而在smalltalk,ruby有却不明显。</P>
<P>类型继承的极致就是C++里的纯虚父类</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_22_101_Open_Image onclick="this.style.display='none'; Codehighlighter1_22_101_Open_Text.style.display='none'; Codehighlighter1_22_101_Closed_Image.style.display='inline'; Codehighlighter1_22_101_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_22_101_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_22_101_Closed_Text.style.display='none'; Codehighlighter1_22_101_Open_Image.style.display='inline'; Codehighlighter1_22_101_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">abstract</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Parent&nbsp;</SPAN><SPAN id=Codehighlighter1_22_101_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_22_101_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;asbtract&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;method1()&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;asbtract&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;method2()&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #000000">0</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>也就是java里的interface</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_17_57_Open_Image onclick="this.style.display='none'; Codehighlighter1_17_57_Open_Text.style.display='none'; Codehighlighter1_17_57_Closed_Image.style.display='inline'; Codehighlighter1_17_57_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_17_57_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_17_57_Closed_Text.style.display='none'; Codehighlighter1_17_57_Open_Image.style.display='inline'; Codehighlighter1_17_57_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Parent&nbsp;</SPAN><SPAN id=Codehighlighter1_17_57_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_17_57_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;method1();<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;method2();<BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>因此，也就明了了，所谓“面向接口编程”是以类型作为约定的编程。我觉得这点大家一定不陌生，面向接口的编程里interface都很小而且约定明确。但是要说明一点的是，这个东西和"面向抽象而不要面向具体编程"其实还不一样，所以这个东西也就仅仅能算是静态类型面向对象的一个惯用法，还到不了原则这么高。</P><img src ="http://www.blogjava.net/raimundox/aggbug/24889.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-21 00:22 <a href="http://www.blogjava.net/raimundox/archive/2005/12/21/24889.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>丧钟为谁鸣？(1)</title><link>http://www.blogjava.net/raimundox/archive/2005/12/20/24851.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Tue, 20 Dec 2005 11:58:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/20/24851.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/24851.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/20/24851.html#Feedback</comments><slash:comments>10</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/24851.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/24851.html</trackback:ping><description><![CDATA[<P>开篇之前先说明一下，我和老庄有着不错的私交，他最初写丧钟系列的时候，我是忠实的拥趸之一，庄兄见我尚有寸尺所长，还在丧钟系列里引用了我的几个观点。然而最近一段时间里，我作了这样几件事情：</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">1</SPAN><SPAN style="COLOR: #000000">.重新学习了lambda演算。我的数学基础不及taowen等，费了一些时日仍不完全了然，目前大抵能对着R5RS后面的语义定义对一些简单的scheme程序进行lambda演算。<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">2</SPAN><SPAN style="COLOR: #000000">.反复研究了几遍SICP。同时看了录像和书（感谢曹老师下的Video），自信对前二章半有些许认识书中未及，后二章半粗知大览尚不能发前人所未发之言。<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">.学习了Smalltalk和Ruby，Duck&nbsp;Typing以及其他一些有关类型系统的东西。<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">.回顾了一下面向对象语言的一些发展史，以史为鉴粗知一些兴替。<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #000000">5</SPAN><SPAN style="COLOR: #000000">.经日和taowen，老庄讨论语言、设计等等之类，每为一辨必穷我所知争发一言，所以知识可以迅速杂糅:D<BR></SPAN></DIV>
<P>经过种种之后，发现当初所谓鸣OO之丧钟，实在是言过其实。<BR>--------------------------------------------------------------------------------------------------------------------------------------------------------------<BR>第0 关于"面向对象"</P>
<P>既然要为人家敲丧钟，先要找对了苦主，不然岂不是白忙活了一场。什么是面向对象？这个问题太大，我们举一个很常见的例子：</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG id=Codehighlighter1_21_84_Open_Image onclick="this.style.display='none'; Codehighlighter1_21_84_Open_Text.style.display='none'; Codehighlighter1_21_84_Closed_Image.style.display='inline'; Codehighlighter1_21_84_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_21_84_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_21_84_Closed_Text.style.display='none'; Codehighlighter1_21_84_Open_Image.style.display='inline'; Codehighlighter1_21_84_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_21_84_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_21_84_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playNote(Note&nbsp;note);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playChord(Chord&nbsp;chord);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG id=Codehighlighter1_131_141_Open_Image onclick="this.style.display='none'; Codehighlighter1_131_141_Open_Text.style.display='none'; Codehighlighter1_131_141_Closed_Image.style.display='inline'; Codehighlighter1_131_141_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_131_141_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_131_141_Closed_Text.style.display='none'; Codehighlighter1_131_141_Open_Image.style.display='inline'; Codehighlighter1_131_141_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top>abstrat&nbsp;</SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Keyboard&nbsp;implement&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_131_141_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_131_141_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">..<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG id=Codehighlighter1_186_196_Open_Image onclick="this.style.display='none'; Codehighlighter1_186_196_Open_Text.style.display='none'; Codehighlighter1_186_196_Closed_Image.style.display='inline'; Codehighlighter1_186_196_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_186_196_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_186_196_Closed_Text.style.display='none'; Codehighlighter1_186_196_Open_Image.style.display='inline'; Codehighlighter1_186_196_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;ClassicGuitar&nbsp;</SPAN><SPAN style="COLOR: #0000ff">implements</SPAN><SPAN style="COLOR: #000000">&nbsp;Instrument&nbsp;</SPAN><SPAN id=Codehighlighter1_186_196_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_186_196_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG id=Codehighlighter1_228_238_Open_Image onclick="this.style.display='none'; Codehighlighter1_228_238_Open_Text.style.display='none'; Codehighlighter1_228_238_Closed_Image.style.display='inline'; Codehighlighter1_228_238_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_228_238_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_228_238_Closed_Text.style.display='none'; Codehighlighter1_228_238_Open_Image.style.display='inline'; Codehighlighter1_228_238_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Piano&nbsp;</SPAN><SPAN style="COLOR: #0000ff">extends</SPAN><SPAN style="COLOR: #000000">&nbsp;Keyboard&nbsp;</SPAN><SPAN id=Codehighlighter1_228_238_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_228_238_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">..<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>in&nbsp;person&nbsp;</SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG id=Codehighlighter1_295_371_Open_Image onclick="this.style.display='none'; Codehighlighter1_295_371_Open_Text.style.display='none'; Codehighlighter1_295_371_Closed_Image.style.display='inline'; Codehighlighter1_295_371_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_295_371_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_295_371_Closed_Text.style.display='none'; Codehighlighter1_295_371_Open_Image.style.display='inline'; Codehighlighter1_295_371_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playSolo(Instrument&nbsp;instrument)&nbsp;</SPAN><SPAN id=Codehighlighter1_295_371_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_295_371_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;instrument.playNote(AbsoluteNote.C1).playNote(AbsoluteNote.C2);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG id=Codehighlighter1_417_481_Open_Image onclick="this.style.display='none'; Codehighlighter1_417_481_Open_Text.style.display='none'; Codehighlighter1_417_481_Closed_Image.style.display='inline'; Codehighlighter1_417_481_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_417_481_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_417_481_Closed_Text.style.display='none'; Codehighlighter1_417_481_Open_Image.style.display='inline'; Codehighlighter1_417_481_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playBackground(Instrument&nbsp;instrument)&nbsp;</SPAN><SPAN id=Codehighlighter1_417_481_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_417_481_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;instrument.playChord(Chord.C5).playChord(Chord.C9);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>in&nbsp;some&nbsp;</SPAN><SPAN style="COLOR: #0000ff">case</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>ClassicGuitar&nbsp;perez711</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>Piano&nbsp;pianoHere&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent.playSolo(stenzel);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>may.playBackground(pianoHere);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>etc<IMG src="http://www.blogjava.net/images/dot.gif">.</SPAN></DIV>
<P>这个例子自然很不充分，不过继承啊，接口啊，多态啊，略举大概，尚可以作为一个讨论的例子。从这个例子里，我们发现有这样一个事实，就是Person类有两个方法</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playSolo(Instrument&nbsp;instrument);<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playBackground(Instrument&nbsp;instrument);</SPAN></DIV>
<P>分别表示，需要一个类型为Instrument的对象instrument，然后对他进行相应的操作，而且，从概念上来讲，第一个方法，使演奏旋律的，也就是单音，而第二个方法是演奏和声的。那么，如果我有一个类</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG id=Codehighlighter1_18_68_Open_Image onclick="this.style.display='none'; Codehighlighter1_18_68_Open_Text.style.display='none'; Codehighlighter1_18_68_Closed_Image.style.display='inline'; Codehighlighter1_18_68_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_18_68_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_18_68_Closed_Text.style.display='none'; Codehighlighter1_18_68_Open_Image.style.display='inline'; Codehighlighter1_18_68_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;GlassBottle&nbsp;</SPAN><SPAN id=Codehighlighter1_18_68_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_18_68_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR><IMG id=Codehighlighter1_49_66_Open_Image onclick="this.style.display='none'; Codehighlighter1_49_66_Open_Text.style.display='none'; Codehighlighter1_49_66_Closed_Image.style.display='inline'; Codehighlighter1_49_66_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_49_66_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_49_66_Closed_Text.style.display='none'; Codehighlighter1_49_66_Open_Image.style.display='inline'; Codehighlighter1_49_66_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">void</SPAN><SPAN style="COLOR: #000000">&nbsp;playNote(Note&nbsp;note)&nbsp;</SPAN><SPAN id=Codehighlighter1_49_66_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_49_66_Open_Text><SPAN style="COLOR: #000000">{<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">..<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>我们知道，玻璃瓶装了水也是可以发出声音，Mozart可是为玻璃瓶写过曲子的，而这里我们却不能</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">GlassBottle&nbsp;beerBottle&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif">.<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent.playSolo(beerBottle);</SPAN></DIV>
<P>因为我们在构造Person类的时候，我们的play方法是依赖一个类型为Instrument的Object，换而言之，我们这里所谓的Object-Oriented其实称作Object-with-Type-Oriented的更合适，其实这类语言有一个专有名词，叫做static type object oriented。那Object-Oriented是不是就一定是Static Type Object Oriented的呢？不然，比如在Ruby里，我们可以写成：</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Person&nbsp;<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;def&nbsp;playSolo(thing)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thing.playNote(Note.C1).playNot(Note.c2)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;def&nbsp;playBackground(thing)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;thing.playChord(Chord.C5).playChord(Chord.C9)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Guitar<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;def&nbsp;playNote(note)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;def&nbsp;playChord(chord)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;GlassBottle<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;def&nbsp;playNote(note)<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>&nbsp;&nbsp;end<BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>end</SPAN></DIV>
<P>然后就可以</P>
<P></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">perez711&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Guitar.</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;Person.</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000"><BR><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>vincent.playSolo(perez711)</SPAN></DIV>
<P>同样也可以</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">vincent.playSolo(GlassBottle.</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">)</SPAN></DIV>
<P>在这里，类型可以推演也可以留到runtime检查，如果是推演的话，在playNote里，由于thing调用了playNote方法，所以传进来的对象必须要刻意接受playNote这个消息，于是Guitar和GlassBottle都是可以通过，因此我即可以演奏我的Perez 711，也可以敲玻璃瓶。这种方式叫做dynamic type。</P>
<P>那么static type和dynamic type区别在那呢？static type认为，class就是type，type就是class; subclass就是subtyping，subtyping就是subclass(其实这句不严谨，在c++里可以使得subclass不是subtyping，但是java里就没办法了);而dynamic type则认为类型和class没有关系，类型取决于一个对象能够接受的消息。</P>
<P>那么哪个才是面向对象之真貌呢？遗憾的说，static type并不是最初的面向对象。以对象作为模块化的单位，始自Simula 67。但是Simula 67并不是一个面向对象系统，以目前的观点来看，充其量是Object-based，第一个面向对象语言当推Smalltalk，Smalltalk是dynamic type的。不过Smalltalk不太流行，第一个大面积流行的面向对象语言是C++，C++是static type的，正如Lisp是第一个函数式编程语言，很多Lisp的特性被当作函数式语言的共有特性(比如表是最重要的数据结构，轻语法)一样，所以很多人以为面向对象就必然是static type（比如老庄和我）。对于面向对象的误解，80%来自C++。也就是说，80%来自于static type的面向对象系统。将static type面向对象归咎于整个面向对象，我辈实在是大而无当言过其实。</P>
<P>后面我再一一将老庄所言之OO不当之处加以说明</P><img src ="http://www.blogjava.net/raimundox/aggbug/24851.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-20 19:58 <a href="http://www.blogjava.net/raimundox/archive/2005/12/20/24851.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>A Walk on JSR220</title><link>http://www.blogjava.net/raimundox/archive/2005/12/12/23427.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Mon, 12 Dec 2005 03:08:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/12/23427.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/23427.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/12/23427.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/23427.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/23427.html</trackback:ping><description><![CDATA[<P>从BJUG的maillist里发掘一个我以前的旧帖出来，嘿嘿<BR><BR>以前我和limo同志做过一个Hibernate技巧情色版..<WBR>..嘿嘿，这次发动大家收集一下J2SE 5和JSR 220里的改进design的tips.我下午试验<SPAN class=st0 id=st name="st">JSR220</SPAN><WBR>的时候，找到几个<BR><BR>1. Implement Moment-Interval and Moment-Interval-Details Using Iterable&lt;T&gt;<BR><BR>例子， 比如Order和OrderItem，典型的一对多<WBR>，一般我们这么做</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_12_106_Open_Image onclick="this.style.display='none'; Codehighlighter1_12_106_Open_Text.style.display='none'; Codehighlighter1_12_106_Closed_Image.style.display='inline'; Codehighlighter1_12_106_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_12_106_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_12_106_Closed_Text.style.display='none'; Codehighlighter1_12_106_Open_Image.style.display='inline'; Codehighlighter1_12_106_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Order&nbsp;</SPAN><SPAN id=Codehighlighter1_12_106_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_12_106_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;List</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">OrderItem</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">&nbsp;items;<BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">5</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_85_104_Open_Image onclick="this.style.display='none'; Codehighlighter1_85_104_Open_Text.style.display='none'; Codehighlighter1_85_104_Closed_Image.style.display='inline'; Codehighlighter1_85_104_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_85_104_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_85_104_Closed_Text.style.display='none'; Codehighlighter1_85_104_Open_Image.style.display='inline'; Codehighlighter1_85_104_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;List</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">OrderItem</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">&nbsp;getItems()&nbsp;</SPAN><SPAN id=Codehighlighter1_85_104_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_85_104_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><IMG src="http://www.blogjava.net/images/dot.gif"><IMG src="http://www.blogjava.net/images/dot.gif"><BR></SPAN><SPAN style="COLOR: #008080">7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P><BR>在J2SE5里面，</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN><IMG id=Codehighlighter1_43_288_Open_Image onclick="this.style.display='none'; Codehighlighter1_43_288_Open_Text.style.display='none'; Codehighlighter1_43_288_Closed_Image.style.display='inline'; Codehighlighter1_43_288_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_43_288_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_43_288_Closed_Text.style.display='none'; Codehighlighter1_43_288_Open_Image.style.display='inline'; Codehighlighter1_43_288_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Order&nbsp;</SPAN><SPAN style="COLOR: #0000ff">implements</SPAN><SPAN style="COLOR: #000000">&nbsp;Iterable</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">OrderItem</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN id=Codehighlighter1_43_288_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_43_288_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;List</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">OrderItem</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">&nbsp;items;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_130_177_Open_Image onclick="this.style.display='none'; Codehighlighter1_130_177_Open_Text.style.display='none'; Codehighlighter1_130_177_Closed_Image.style.display='inline'; Codehighlighter1_130_177_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_130_177_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_130_177_Closed_Text.style.display='none'; Codehighlighter1_130_177_Open_Image.style.display='inline'; Codehighlighter1_130_177_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;Iterator</SPAN><SPAN style="COLOR: #000000">&lt;</SPAN><SPAN style="COLOR: #000000">OrderItem</SPAN><SPAN style="COLOR: #000000">&gt;</SPAN><SPAN style="COLOR: #000000">&nbsp;iterator()&nbsp;</SPAN><SPAN id=Codehighlighter1_130_177_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_130_177_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;items.iterator;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_212_243_Open_Image onclick="this.style.display='none'; Codehighlighter1_212_243_Open_Text.style.display='none'; Codehighlighter1_212_243_Closed_Image.style.display='inline'; Codehighlighter1_212_243_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_212_243_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_212_243_Closed_Text.style.display='none'; Codehighlighter1_212_243_Open_Image.style.display='inline'; Codehighlighter1_212_243_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">int</SPAN><SPAN style="COLOR: #000000">&nbsp;getItemCount()&nbsp;</SPAN><SPAN id=Codehighlighter1_212_243_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_212_243_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">10</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&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"><IMG src="http://www.blogjava.net/images/dot.gif"><BR></SPAN><SPAN style="COLOR: #008080">11</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">12</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;and&nbsp;addItem&nbsp;removeItem&nbsp;and&nbsp;others</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">13</SPAN><SPAN style="COLOR: #008000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></SPAN><SPAN style="COLOR: #000000">}</SPAN></SPAN></DIV>
<P>就可以直接来处理，</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_29_31_Open_Image onclick="this.style.display='none'; Codehighlighter1_29_31_Open_Text.style.display='none'; Codehighlighter1_29_31_Closed_Image.style.display='inline'; Codehighlighter1_29_31_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_29_31_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_29_31_Closed_Text.style.display='none'; Codehighlighter1_29_31_Open_Image.style.display='inline'; Codehighlighter1_29_31_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">for</SPAN><SPAN style="COLOR: #000000">&nbsp;(OrderItem&nbsp;item&nbsp;:&nbsp;order)&nbsp;</SPAN><SPAN id=Codehighlighter1_29_31_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_29_31_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>从某种程度上利用enhanced for的语法，来简化语法。<BR><BR>trade-off: 不适合多个details 聚合，适合于简单的moment-interval和momen<WBR>t-interval-details。<BR><BR>2. Annotate Description with @Embeddable, and the Thing it describe with @Entity<BR><BR>例子，Product和ProductDescription</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">@Embeddable<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_37_126_Open_Image onclick="this.style.display='none'; Codehighlighter1_37_126_Open_Text.style.display='none'; Codehighlighter1_37_126_Closed_Image.style.display='inline'; Codehighlighter1_37_126_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_37_126_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_37_126_Closed_Text.style.display='none'; Codehighlighter1_37_126_Open_Image.style.display='inline'; Codehighlighter1_37_126_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;ProductDescription&nbsp;</SPAN><SPAN id=Codehighlighter1_37_126_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_37_126_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;String&nbsp;name;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;String&nbsp;description;<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;<IMG src="http://www.blogjava.net/images/dot.gif"><IMG src="http://www.blogjava.net/images/dot.gif">.&nbsp;and&nbsp;getters&nbsp;and&nbsp;setters<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>@Entity(access&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;AccessType.FIELD)<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_178_222_Open_Image onclick="this.style.display='none'; Codehighlighter1_178_222_Open_Text.style.display='none'; Codehighlighter1_178_222_Closed_Image.style.display='inline'; Codehighlighter1_178_222_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_178_222_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_178_222_Closed_Text.style.display='none'; Codehighlighter1_178_222_Open_Image.style.display='inline'; Codehighlighter1_178_222_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;Product&nbsp;</SPAN><SPAN id=Codehighlighter1_178_222_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_178_222_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">10</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;ProdcutDescription&nbsp;description;<BR></SPAN><SPAN style="COLOR: #008080">11</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>在<SPAN class=st0 id=st name="st">JSR220</SPAN>里，如果一个field是embeddable<WBR>，而且对该field没有标注为@Transite<WBR>,以及使用keyword transite,自动按Embedded处理，这一点是很方便<WBR>的。<BR><BR>这个基本没发现trade-off<BR><BR><BR>3. Avoid Database Primary Key in Domain Model Using @EmbeddableSuperclass<BR><BR>例子，在hibernate里，总是要给Domain加一个pr<WBR>imary key，非常的不爽.<BR>虽然也可以通过继承结构来避免，但是配置文件太多， <SPAN class=st0 id=st name="st">JSR220</SPAN>里，通过自动处理的annotation<WBR>
<SCRIPT><!--
D(["mb","，可以节约很大的工作量。<br /><br />@EmbeddableSuperclass<br />class DomainModel {<br />// &nbsp;modeling your model here<br />}<br /><br />@Entity<br />class PersistentDomainModel extends DomainModel {<br /><br /> &nbsp; &nbsp;private long primaryKey;<br />}<br /><br />这个大家就一目了然了<br /><br />4. Avoid Database Field in Domain Model Using @AttributeOverride<br /><br /><br />Annotation虽然简化了开发，但是仍然有一个问题<wbr />，就是修改mapping的时候需要修改代码，这个很不好<wbr />，而且影射的时候需要在domain里硬编码field<br />name，这个简直就是恶心，但是还是由办法避免的。<br /><br />@EmbeddableSuperclass<br />class DomainModel {<br />// &nbsp;modeling your model here<br />}<br /><br /><br />@Entity<br />@AttributeOverride(name\u003d<wbr />&quot;property&quot;, column\u003d@Column(name\u003d&quot;fieldName<wbr />&quot;))<br />class PersistentDomainModel extends DomainModel {<br /><br /> &nbsp; &nbsp;private long primaryKey;<br />}<br /><br />同样，通过继承来隔离技术和Domain，然后在子类里作部署相<wbr />关的动作。然后把DomainModel<br />和PersistentDomainModel 分包，针对DomainModel编程，就Ok了<wbr />。这个时候Domain会异常的干净.....<br /><br />5. Model Place as Factory<br /><br />其实这个是一个通则，以前好像也讨论过。<br /><br />public interface Store {<br /> &nbsp; Order newOrder();<br /> &nbsp; // and others;<br />}<br /><br />基本上下午2个小时的成果就这么多，我是在尝试用JSR220<br />API代替以前我和limo写的那个珍珠商城订单部分得到的一些<wbr />tips。总体而言，JSR220还是挺好的，我们可以很自然的<wbr />运用一些模式和OO的手段还避免它的不足。同时上述做法在hib<wbr />ernate里也可以做，但是由于比较麻烦，大家一般还是做不到<wbr />。JSR220里，正是通过它的毛病强迫我们这么做.....<wbr />（汗），也算体现出约定了。<br />",0]
);

//--></SCRIPT>
 ，可以节约很大的工作量。<BR></P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">@EmbeddableSuperclass<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_40_71_Open_Image onclick="this.style.display='none'; Codehighlighter1_40_71_Open_Text.style.display='none'; Codehighlighter1_40_71_Closed_Image.style.display='inline'; Codehighlighter1_40_71_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_40_71_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_40_71_Closed_Text.style.display='none'; Codehighlighter1_40_71_Open_Image.style.display='inline'; Codehighlighter1_40_71_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;DomainModel&nbsp;</SPAN><SPAN id=Codehighlighter1_40_71_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_40_71_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;modeling&nbsp;your&nbsp;model&nbsp;here</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #008000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></SPAN><SPAN style="COLOR: #000000">}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>@Entity<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_130_161_Open_Image onclick="this.style.display='none'; Codehighlighter1_130_161_Open_Text.style.display='none'; Codehighlighter1_130_161_Closed_Image.style.display='inline'; Codehighlighter1_130_161_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_130_161_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_130_161_Closed_Text.style.display='none'; Codehighlighter1_130_161_Open_Image.style.display='inline'; Codehighlighter1_130_161_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;PersistentDomainModel&nbsp;</SPAN><SPAN style="COLOR: #0000ff">extends</SPAN><SPAN style="COLOR: #000000">&nbsp;DomainModel&nbsp;</SPAN><SPAN id=Codehighlighter1_130_161_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_130_161_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">&nbsp;primaryKey;<BR></SPAN><SPAN style="COLOR: #008080">10</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>这个大家就一目了然了<BR><BR>4. Avoid Database Field in Domain Model Using @AttributeOverride<BR><BR><BR>Annotation虽然简化了开发，但是仍然有一个问题<WBR>，就是修改mapping的时候需要修改代码，这个很不好<WBR>，而且影射的时候需要在domain里硬编码field<BR>name，这个简直就是恶心，但是还是由办法避免的。</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">@EmbeddableSuperclass<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_40_71_Open_Image onclick="this.style.display='none'; Codehighlighter1_40_71_Open_Text.style.display='none'; Codehighlighter1_40_71_Closed_Image.style.display='inline'; Codehighlighter1_40_71_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_40_71_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_40_71_Closed_Text.style.display='none'; Codehighlighter1_40_71_Open_Image.style.display='inline'; Codehighlighter1_40_71_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;DomainModel&nbsp;</SPAN><SPAN id=Codehighlighter1_40_71_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_40_71_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top></SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;&nbsp;modeling&nbsp;your&nbsp;model&nbsp;here</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #008000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></SPAN><SPAN style="COLOR: #000000">}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>@Entity<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top>@AttributeOverride(name</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">property</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">,&nbsp;column</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">@Column(name</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">fieldName</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">))<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_201_232_Open_Image onclick="this.style.display='none'; Codehighlighter1_201_232_Open_Text.style.display='none'; Codehighlighter1_201_232_Closed_Image.style.display='inline'; Codehighlighter1_201_232_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_201_232_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_201_232_Closed_Text.style.display='none'; Codehighlighter1_201_232_Open_Image.style.display='inline'; Codehighlighter1_201_232_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;PersistentDomainModel&nbsp;</SPAN><SPAN style="COLOR: #0000ff">extends</SPAN><SPAN style="COLOR: #000000">&nbsp;DomainModel&nbsp;</SPAN><SPAN id=Codehighlighter1_201_232_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_201_232_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">10</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">11</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">private</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">long</SPAN><SPAN style="COLOR: #000000">&nbsp;primaryKey;<BR></SPAN><SPAN style="COLOR: #008080">12</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN></DIV>
<P>同样，通过继承来隔离技术和Domain，然后在子类里作部署相<WBR>关的动作。然后把DomainModel和PersistentDomainModel 分包，针对DomainModel编程，就Ok了<WBR>。这个时候Domain会异常的干净.....<BR><BR>5. Model Place as Factory<BR><BR>其实这个是一个通则，以前好像也讨论过。</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG id=Codehighlighter1_23_62_Open_Image onclick="this.style.display='none'; Codehighlighter1_23_62_Open_Text.style.display='none'; Codehighlighter1_23_62_Closed_Image.style.display='inline'; Codehighlighter1_23_62_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_23_62_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_23_62_Closed_Text.style.display='none'; Codehighlighter1_23_62_Open_Image.style.display='inline'; Codehighlighter1_23_62_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">interface</SPAN><SPAN style="COLOR: #000000">&nbsp;Store&nbsp;</SPAN><SPAN id=Codehighlighter1_23_62_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_23_62_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;Order&nbsp;newOrder();<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #008000">//</SPAN><SPAN style="COLOR: #008000">&nbsp;and&nbsp;others;</SPAN><SPAN style="COLOR: #008000"><BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #008000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top></SPAN><SPAN style="COLOR: #000000">}</SPAN></SPAN></DIV>
<P>基本上下午2个小时的成果就这么多，我是在尝试用<SPAN class=st0 id=st name="st">JSR220 </SPAN>API代替以前我和limo写的那个珍珠商城订单部分得到的一些<WBR>tips。总体而言，<SPAN class=st0 id=st name="st">JSR220</SPAN>还是挺好的，我们可以很自然的<WBR>运用一些模式和OO的手段还避免它的不足。同时上述做法在hib<WBR>ernate里也可以做，但是由于比较麻烦，大家一般还是做不到<WBR>。<SPAN class=st0 id=st name="st">JSR220</SPAN>里，正是通过它的毛病强迫我们这么做.....<WBR>（汗），也算体现出约定了。</P><img src ="http://www.blogjava.net/raimundox/aggbug/23427.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-12 11:08 <a href="http://www.blogjava.net/raimundox/archive/2005/12/12/23427.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Why Inconsistent Concepts Considered Harmful</title><link>http://www.blogjava.net/raimundox/archive/2005/12/10/23238.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Fri, 09 Dec 2005 18:17:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/10/23238.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/23238.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/10/23238.html#Feedback</comments><slash:comments>2</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/23238.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/23238.html</trackback:ping><description><![CDATA[<p>小tao给我找了一个非常好的题目:</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 0);">so,&nbsp;you&nbsp;think&nbsp;the&nbsp;consistent&nbsp;thing&nbsp;means&nbsp;a&nbsp;lot</span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);">&nbsp;But&nbsp;how&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">&nbsp;you&nbsp;think&nbsp;the&nbsp;gracious&nbsp;or&nbsp;elegant&nbsp;feeling&nbsp;mean&nbsp;to&nbsp;the&nbsp;real&nbsp;expressiveness&nbsp;of&nbsp;business&nbsp;requirements</span><span style="color: rgb(0, 0, 0);">?</span><span style="color: rgb(0, 0, 0);">&nbsp;We&nbsp;can&nbsp;see&nbsp;lisp&nbsp;is&nbsp;very&nbsp;successful&nbsp;in&nbsp;researching&nbsp;area&nbsp;because&nbsp;of&nbsp;the&nbsp;simplicity&nbsp;nature&nbsp;inside&nbsp;which&nbsp;is&nbsp;also&nbsp;</span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">&nbsp;to&nbsp;Smalltalk.&nbsp;But&nbsp;why&nbsp;they&nbsp;aren</span><span style="color: rgb(0, 0, 0);">'</span><span style="color: rgb(0, 0, 0);">t&nbsp;successful&nbsp;in&nbsp;biz&nbsp;world?&nbsp;I&nbsp;think&nbsp;that&nbsp;is&nbsp;the&nbsp;problem&nbsp;you&nbsp;should&nbsp;further&nbsp;study,&nbsp;"how&nbsp;can&nbsp;the&nbsp;consistent&nbsp;feeling&nbsp;mean&nbsp;something&nbsp;to&nbsp;our&nbsp;everyday&nbsp;programming&nbsp;life?".</span></div>
<p><br>我承认以前没有考虑到这个问题，因为我以为追求概念一致性是一种不言自明的天性。那么为什么要一致性很重要呢？我有这样一些想法。</p>
<p>1. 复杂性</p>
<p>概念不一致产生首先产生的一个恶果就是复杂性，这里我将举两个例子。<br><br>第一个关于Lisp的。Lisp本身具有一个很一致很简单的计算模型——λ 演算。在这个计算模型中，基本元素是函数，λ运算符，·运算符。语义也是简单明确的，lambda运算符提取出函数中的自由变量，然后再由apply对自由变量赋值。整个计算过程就是函数（符号）求值的过程。例如对于函数x + y，我们可以这样来求值。</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">((λx&nbsp;(λy&nbsp;.&nbsp;x&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;y)·</span><span style="color: rgb(0, 0, 0);">3</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);">)<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"></span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">((λx.&nbsp;x</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">3</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);">)<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"></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);">&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);"><br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"></span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">7</span></div>
<p>由于Lisp多少可以认为是λ 演算的一种实现，我们可以类似写出Lisp代码</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 0);">(define&nbsp;f&nbsp;(lambda&nbsp;x&nbsp;(lambda&nbsp;y&nbsp;(</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;x&nbsp;y))))<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">(apply&nbsp;(apply&nbsp;f&nbsp;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">)&nbsp;</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">)</span></div>
<p>或者更加简单的写为</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 0);">(define&nbsp;(f&nbsp;x&nbsp;y)&nbsp;(</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;x&nbsp;y))<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">(f&nbsp;</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">)</span></div>
<p>所有在Lisp中的程序，我们都可以用一种一致的概念来表达，就是符号求值，我们对一个符号应用一些值，然后这个符号完成计算并把结构返回给我们，在计算的过程中，符号对外部环境没有任何破坏和依赖。但是Lisp中引入了赋值，于是存在一些符号，不仅仅是来计算，同时他们还能改变环境。</p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 0);">(define&nbsp;(bad</span><span style="color: rgb(0, 0, 0);">-</span><span style="color: rgb(0, 0, 0);">f&nbsp;x&nbsp;y)&nbsp;<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;(begin&nbsp;<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(set</span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">&nbsp;z&nbsp;</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">)<br><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;(</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;x&nbsp;y)))</span></div>
<p>这个函数不仅仅求x + y的值，同时修改了符号Z的值。赋值的引入破坏了函数只求值而不影响环境这个概念的一致性。于是我们不得不寻找一个更加复杂的也更加混乱的计算模型，来代替简单优雅的λ 演算。于是不一致的概念带来了思维上的复杂性(不过Lisp中的概念不一致除了产生了复杂之外，还激发了人们对于简单计算模型的向往从而产生了函数式编程风格，这也是我最爱的编程风格之一)。</p>
<p>概念不一致带来的复杂性距离我们最近的应该是Java中的简单类型，Java本身是一个单根的面向对象语言，从概念上讲一切都应该是对象，而且由于性能考虑而出现的简单类型，引入了代数性的世界观的同时，破坏了面向对象的一致概念。Java中虽然有包装类来做补偿，但是仍然不能弥补概念上的断裂。我们可以用 </p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 128, 128);">1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">)</span></div>
<p>来代表对象概念中的3，但是</p>
<p>3 + 4 * 5</p>
<p>不能对等的翻译为:</p>
<p></p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 128, 128);">1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">3</span><span style="color: rgb(0, 0, 0);">)&nbsp;</span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">4</span><span style="color: rgb(0, 0, 0);">)&nbsp;</span><span style="color: rgb(0, 0, 0);">*</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);">&nbsp;Integer(</span><span style="color: rgb(0, 0, 0);">5</span><span style="color: rgb(0, 0, 0);">)</span></div>
<p>简单类型具有的运算符和对象类型的消息发送概念上是不一致的。虽然我们可以在Java 5中使用上述的代码，但是Java 5的Auto-Boxing更多的把对象类型当作简单类型进行数据运算，而不是像C++中的运算符重载一样把数据运算当作一种特殊消息传递，虽然语法上有相似的功能，但是概念上大异其趣，对于我这个OO分子而言，Java 5的Auto-Boxing实在是恶心到不行。同时简单类型和对象类型在赋值语义和存储模型上也存在很大的不一致，这种不一致性在使用Collection API的时候带来了一些复杂度。（还记得Commons Collection里那些Primitive Collection吧？）<br><br>2.副作用</p>
<p>概念不一致产生的第二个恶果就是副作用，我大概想了一下都有哪些可能的副作用，结果让我很寒，我能想到的副作用，大多数是由于在另一种模型中引入了冯语言的因素从而造成了概念上的不一致而引起的。其中最为人知的....还是赋值在函数式编程中的副作用...这个在函数式编程社区有很广泛的讨论，我只说一点，为什么命令语言是有害的。</p>
<p>冯语言或者说命令式语言主要用于刻画对计算机操作的序列，并不关心序列的内在关系。也就是说，我们可以把一些完全没有联系的指令写在一起。因此冯语言在语义上毫无建树，同时在抽象上也止步于子程序（一砣指令和另一砣指令）。冯语言具有很强的时间耦合性在存储上也强烈的倾向于线性存储。目前大多数难处理的问题，可以归结为计算模型和操作语义的不一致，甚至有些学者认为是冯结构严重制约了计算机的发展。因此冯语言被函数社区看作一个很危险的副作用，极力避免之。</p>
<p>概念的不一致产生的副作用在混血的OO语言中也很明显，尤其是在命令式语言中加入面向对象机制，而且使用面向对象作为类型系统的扩展，使用过程式的方法来控制流程。过程和对象的不一致本身就给了程序员一种暗示，你可以使用对象技术来构造类型系统，然后使用过程的方法来操作他。明显的副作用们很容易使用过程化程序，从而使得对象带来的好处被很大的削弱了（当然我们有重构来弥补这个错误），比如下面一个例子,我们很容易从写出下面的代码：</p>
<p></p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 128, 128);">1</span><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">&nbsp;(order.getState()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;Order.CANCEL)<br></span><span style="color: rgb(0, 128, 128);">2</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">&nbsp;something&nbsp;</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">&nbsp;cancel;<br></span><span style="color: rgb(0, 128, 128);">3</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"></span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(order.getState()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;Order.PAID)<br></span><span style="color: rgb(0, 128, 128);">4</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">&nbsp;something&nbsp;</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">&nbsp;paid;<br></span><span style="color: rgb(0, 128, 128);">5</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"></span><span style="color: rgb(0, 0, 255);">else</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);">(order.getState()&nbsp;</span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);">&nbsp;Order.DELIVERY)<br></span><span style="color: rgb(0, 128, 128);">6</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">&nbsp;something&nbsp;</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">&nbsp;delivery</span></div>
<p>而不是<br></p>
<p></p>
<div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; font-size: 13px; width: 98%; background-color: rgb(238, 238, 238);"><span style="color: rgb(0, 128, 128);">&nbsp;1</span><img id="Codehighlighter1_27_166_Open_Image" onclick="this.style.display='none'; Codehighlighter1_27_166_Open_Text.style.display='none'; Codehighlighter1_27_166_Closed_Image.style.display='inline'; Codehighlighter1_27_166_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_27_166_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_27_166_Closed_Text.style.display='none'; Codehighlighter1_27_166_Open_Image.style.display='inline'; Codehighlighter1_27_166_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);">&nbsp;OrderState&nbsp;</span><span id="Codehighlighter1_27_166_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="http://www.blogjava.net/images/dot.gif"></span><span id="Codehighlighter1_27_166_Open_Text"><span style="color: rgb(0, 0, 0);">{<br></span><span style="color: rgb(0, 128, 128);">&nbsp;2</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"><br></span><span style="color: rgb(0, 128, 128);">&nbsp;3</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">protected</span><span style="color: rgb(0, 0, 0);">&nbsp;Order&nbsp;_order;<br></span><span style="color: rgb(0, 128, 128);">&nbsp;4</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">&nbsp;5</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_97_124_Open_Image" onclick="this.style.display='none'; Codehighlighter1_97_124_Open_Text.style.display='none'; Codehighlighter1_97_124_Closed_Image.style.display='inline'; Codehighlighter1_97_124_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_97_124_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_97_124_Closed_Text.style.display='none'; Codehighlighter1_97_124_Open_Image.style.display='inline'; Codehighlighter1_97_124_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">protected</span><span style="color: rgb(0, 0, 0);">&nbsp;OrderState(Order&nbsp;order)</span><span id="Codehighlighter1_97_124_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="http://www.blogjava.net/images/dot.gif"></span><span id="Codehighlighter1_97_124_Open_Text"><span style="color: rgb(0, 0, 0);">{<br></span><span style="color: rgb(0, 128, 128);">&nbsp;6</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;_order&nbsp;</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">&nbsp;order;<br></span><span style="color: rgb(0, 128, 128);">&nbsp;7</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">&nbsp;8</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;<br></span><span style="color: rgb(0, 128, 128);">&nbsp;9</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">abstract</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;handler();<br></span><span style="color: rgb(0, 128, 128);">10</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">11</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><br></span><span style="color: rgb(0, 128, 128);">12</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_206_272_Open_Image" onclick="this.style.display='none'; Codehighlighter1_206_272_Open_Text.style.display='none'; Codehighlighter1_206_272_Closed_Image.style.display='inline'; Codehighlighter1_206_272_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align="top"><img id="Codehighlighter1_206_272_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_206_272_Closed_Text.style.display='none'; Codehighlighter1_206_272_Open_Image.style.display='inline'; Codehighlighter1_206_272_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align="top"></span><span style="color: rgb(0, 0, 255);">class</span><span style="color: rgb(0, 0, 0);">&nbsp;CancelState&nbsp;</span><span style="color: rgb(0, 0, 255);">extends</span><span style="color: rgb(0, 0, 0);">&nbsp;OrderState&nbsp;</span><span id="Codehighlighter1_206_272_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="http://www.blogjava.net/images/dot.gif"></span><span id="Codehighlighter1_206_272_Open_Text"><span style="color: rgb(0, 0, 0);">{<br></span><span style="color: rgb(0, 128, 128);">13</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top"><br></span><span style="color: rgb(0, 128, 128);">14</span><span style="color: rgb(0, 0, 0);"><img id="Codehighlighter1_234_270_Open_Image" onclick="this.style.display='none'; Codehighlighter1_234_270_Open_Text.style.display='none'; Codehighlighter1_234_270_Closed_Image.style.display='inline'; Codehighlighter1_234_270_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align="top"><img id="Codehighlighter1_234_270_Closed_Image" style="display: none;" onclick="this.style.display='none'; Codehighlighter1_234_270_Closed_Text.style.display='none'; Codehighlighter1_234_270_Open_Image.style.display='inline'; Codehighlighter1_234_270_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align="top">&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);">&nbsp;</span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);">&nbsp;handler()&nbsp;</span><span id="Codehighlighter1_234_270_Closed_Text" style="border: 1px solid rgb(128, 128, 128); display: none; background-color: rgb(255, 255, 255);"><img src="http://www.blogjava.net/images/dot.gif"></span><span id="Codehighlighter1_234_270_Open_Text"><span style="color: rgb(0, 0, 0);">{<br></span><span style="color: rgb(0, 128, 128);">15</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align="top">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</span><span style="color: rgb(0, 0, 255);">do</span><span style="color: rgb(0, 0, 0);">&nbsp;something&nbsp;</span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);">&nbsp;cancel;<br></span><span style="color: rgb(0, 128, 128);">16</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align="top">&nbsp;&nbsp;&nbsp;}</span></span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">17</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align="top">}</span></span><span style="color: rgb(0, 0, 0);"><br></span><span style="color: rgb(0, 128, 128);">18</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top"><br></span><span style="color: rgb(0, 128, 128);">19</span><span style="color: rgb(0, 0, 0);"><img src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align="top">order.getState().handle();</span></div><p>因为存在过程性的关键字if, while,处于方便的考虑，我们会写出第一种风格的代码，而考虑到易于维护，我们应该写第二种风格的代码。存在两种不一致的书写代码的风格，这个时候，副作用取决于使用的语言OO的程度，比如在C++里更容易写出第一种风格的代码，而在Ruby和Smalltalk中，更容易写出第二种风格的代码。<br></p><p>3.递归的构造软件</p>
<p>这个虽然跟概念一致有关，但是一个更大的主题，待续吧。</p>
<p>4.优雅，美感和无名品质</p>
<p>概念的一致性会产生一种优雅的美感，我觉得我们都有这种感觉，如果我们能用一种一致的容易理解且统一的方式来处理多种不同的复杂的问题，那么我们就会觉得这种方法很优雅，也很具有美感。类比物理中的牛顿定律，开普勒定律，麦克斯韦方程，都是这种简单一致而解决复杂问题的完美示例。我们更容易感觉到一致的感念产生的美感，而不一致的概念往往很难令我欣赏。或许无名品质是我对一致的概念的一种模糊的审美吧。</p>
<p>我大抵能想到的就这么多，不知小tao是否满意我的答卷。</p>
<p>&nbsp;</p><img src ="http://www.blogjava.net/raimundox/aggbug/23238.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-10 02:17 <a href="http://www.blogjava.net/raimundox/archive/2005/12/10/23238.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Apologize to Object-Oriented Methodology</title><link>http://www.blogjava.net/raimundox/archive/2005/12/08/22986.html</link><dc:creator>Raimundox</dc:creator><author>Raimundox</author><pubDate>Thu, 08 Dec 2005 07:11:00 GMT</pubDate><guid>http://www.blogjava.net/raimundox/archive/2005/12/08/22986.html</guid><wfw:comment>http://www.blogjava.net/raimundox/comments/22986.html</wfw:comment><comments>http://www.blogjava.net/raimundox/archive/2005/12/08/22986.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.blogjava.net/raimundox/comments/commentRss/22986.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/raimundox/services/trackbacks/22986.html</trackback:ping><description><![CDATA[<P>最近学习了一下Smalltalk，然后深深的喜欢上了这个古老的语言。Smalltalk语言只具有一个很小的语言核心，这个核心由大约10几个关键字和一些基础的面向对象语义构成。而且关键字都是象: . ; ( ) [ ] | := 之类的简单符号，并没有提供最基本控制的流程。最开始的时候这让我很迷惑，虽然循环结构可以用递归表示，但是分支怎么办？然后发现了一个很酷的特性，Smalltalk可以仅仅通过面向对象的语义来实现分支结构（其实就是State Pattern），具体的代码如下</P>
<P>Boolean&gt;&gt;ifTrue: aBlock<BR>&nbsp; self subclassResponsibility</P>
<P>Boolean&gt;&gt;ifFalse: aBlock<BR>&nbsp; self subclassResponsibility</P>
<P>True&gt;&gt;ifTrue: aBlock<BR>&nbsp; ^aBlock value.</P>
<P>True&gt;&gt;ifFalse: aBlock<BR>&nbsp; ^nil.</P>
<P>False&gt;&gt;ifTrue: aBlock<BR>&nbsp; ^nil.</P>
<P>False&gt;&gt;ifFalse: aBlock<BR>&nbsp; ^aBlock value.</P>
<P>然后就可以，</P>
<P>4 〉3 ifTrue: [Transcript show: 'Hello']</P>
<P>因为在Smalltalk里，一切皆对象且从左到右求值，于是4 &gt; 3 返回true，true是类True的唯一实例，然后就可以对它发送消息，ifTrue:，于是调用了^aBlock value.来对传进去的BlockClosure求值。</P>
<P><BR>下面是类似的java的类似代码。</P>
<P>&nbsp;</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">&nbsp;1</SPAN><IMG id=Codehighlighter1_30_216_Open_Image onclick="this.style.display='none'; Codehighlighter1_30_216_Open_Text.style.display='none'; Codehighlighter1_30_216_Closed_Image.style.display='inline'; Codehighlighter1_30_216_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_30_216_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_30_216_Closed_Text.style.display='none'; Codehighlighter1_30_216_Open_Image.style.display='inline'; Codehighlighter1_30_216_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">abstract</SPAN><SPAN style="COLOR: #000000">&nbsp;Boolean&nbsp;</SPAN><SPAN id=Codehighlighter1_30_216_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_30_216_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;2</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&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">final</SPAN><SPAN style="COLOR: #000000">&nbsp;TRUE&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;True();<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;3</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&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">final</SPAN><SPAN style="COLOR: #000000">&nbsp;FALSE&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;False();<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&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;Object&nbsp;ifTrue(Block&nbsp;aBlock);<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&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;Object&nbsp;ifFalse(Block&nbsp;aBlock);<BR></SPAN><SPAN style="COLOR: #008080">&nbsp;7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">&nbsp;9</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_246_393_Open_Image onclick="this.style.display='none'; Codehighlighter1_246_393_Open_Text.style.display='none'; Codehighlighter1_246_393_Closed_Image.style.display='inline'; Codehighlighter1_246_393_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_246_393_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_246_393_Closed_Text.style.display='none'; Codehighlighter1_246_393_Open_Image.style.display='inline'; Codehighlighter1_246_393_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;True&nbsp;</SPAN><SPAN style="COLOR: #0000ff">extends</SPAN><SPAN style="COLOR: #000000">&nbsp;Boolean&nbsp;</SPAN><SPAN id=Codehighlighter1_246_393_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_246_393_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">10</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">11</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_287_324_Open_Image onclick="this.style.display='none'; Codehighlighter1_287_324_Open_Text.style.display='none'; Codehighlighter1_287_324_Closed_Image.style.display='inline'; Codehighlighter1_287_324_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_287_324_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_287_324_Closed_Text.style.display='none'; Codehighlighter1_287_324_Open_Image.style.display='inline'; Codehighlighter1_287_324_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;Object&nbsp;ifTrue(Block&nbsp;aBlock)&nbsp;</SPAN><SPAN id=Codehighlighter1_287_324_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_287_324_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">12</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;aBlock.execute();<BR></SPAN><SPAN style="COLOR: #008080">13</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">14</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">15</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_366_391_Open_Image onclick="this.style.display='none'; Codehighlighter1_366_391_Open_Text.style.display='none'; Codehighlighter1_366_391_Closed_Image.style.display='inline'; Codehighlighter1_366_391_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_366_391_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_366_391_Closed_Text.style.display='none'; Codehighlighter1_366_391_Open_Image.style.display='inline'; Codehighlighter1_366_391_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;Object&nbsp;ifFalse(Block&nbsp;aBlock)&nbsp;</SPAN><SPAN id=Codehighlighter1_366_391_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_366_391_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">16</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">17</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">18</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">19</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">20</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_424_578_Open_Image onclick="this.style.display='none'; Codehighlighter1_424_578_Open_Text.style.display='none'; Codehighlighter1_424_578_Closed_Image.style.display='inline'; Codehighlighter1_424_578_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_424_578_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_424_578_Closed_Text.style.display='none'; Codehighlighter1_424_578_Open_Image.style.display='inline'; Codehighlighter1_424_578_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top></SPAN><SPAN style="COLOR: #0000ff">class</SPAN><SPAN style="COLOR: #000000">&nbsp;False&nbsp;</SPAN><SPAN style="COLOR: #0000ff">extends</SPAN><SPAN style="COLOR: #000000">&nbsp;Boolean&nbsp;</SPAN><SPAN id=Codehighlighter1_424_578_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_424_578_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">21</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">22</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_465_490_Open_Image onclick="this.style.display='none'; Codehighlighter1_465_490_Open_Text.style.display='none'; Codehighlighter1_465_490_Closed_Image.style.display='inline'; Codehighlighter1_465_490_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_465_490_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_465_490_Closed_Text.style.display='none'; Codehighlighter1_465_490_Open_Image.style.display='inline'; Codehighlighter1_465_490_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;Object&nbsp;ifTrue(Block&nbsp;aBlock)&nbsp;</SPAN><SPAN id=Codehighlighter1_465_490_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_465_490_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">23</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">24</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">25</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">26</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_532_576_Open_Image onclick="this.style.display='none'; Codehighlighter1_532_576_Open_Text.style.display='none'; Codehighlighter1_532_576_Closed_Image.style.display='inline'; Codehighlighter1_532_576_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_532_576_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_532_576_Closed_Text.style.display='none'; Codehighlighter1_532_576_Open_Image.style.display='inline'; Codehighlighter1_532_576_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;Object&nbsp;ifFalse(Block&nbsp;aBlock)&nbsp;</SPAN><SPAN id=Codehighlighter1_532_576_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_532_576_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">27</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;aBlock.execute();&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;<BR></SPAN><SPAN style="COLOR: #008080">28</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">29</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">30</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN></DIV>
<P>4 〉3 ifTrue: [Transcript show: 'Hello']就可以对应翻译为:</P>
<P>&nbsp;</P>
<DIV style="BORDER-RIGHT: #cccccc 1px solid; PADDING-RIGHT: 5px; BORDER-TOP: #cccccc 1px solid; PADDING-LEFT: 4px; FONT-SIZE: 13px; PADDING-BOTTOM: 4px; BORDER-LEFT: #cccccc 1px solid; WIDTH: 98%; WORD-BREAK: break-all; PADDING-TOP: 4px; BORDER-BOTTOM: #cccccc 1px solid; BACKGROUND-COLOR: #eeeeee"><SPAN style="COLOR: #008080">1</SPAN><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><SPAN style="COLOR: #000000">Boolean&nbsp;condition&nbsp;</SPAN><SPAN style="COLOR: #000000">=</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;Integer(</SPAN><SPAN style="COLOR: #000000">4</SPAN><SPAN style="COLOR: #000000">).isGreaterThan(</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;Integer(</SPAN><SPAN style="COLOR: #000000">3</SPAN><SPAN style="COLOR: #000000">));<BR></SPAN><SPAN style="COLOR: #008080">2</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_102_192_Open_Image onclick="this.style.display='none'; Codehighlighter1_102_192_Open_Text.style.display='none'; Codehighlighter1_102_192_Closed_Image.style.display='inline'; Codehighlighter1_102_192_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockStart.gif" align=top><IMG id=Codehighlighter1_102_192_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_102_192_Closed_Text.style.display='none'; Codehighlighter1_102_192_Open_Image.style.display='inline'; Codehighlighter1_102_192_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedBlock.gif" align=top>condition.ifTrue(</SPAN><SPAN style="COLOR: #0000ff">new</SPAN><SPAN style="COLOR: #000000">&nbsp;BlockClosure()&nbsp;</SPAN><SPAN id=Codehighlighter1_102_192_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_102_192_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">3</SPAN><SPAN style="COLOR: #000000"><IMG id=Codehighlighter1_131_190_Open_Image onclick="this.style.display='none'; Codehighlighter1_131_190_Open_Text.style.display='none'; Codehighlighter1_131_190_Closed_Image.style.display='inline'; Codehighlighter1_131_190_Closed_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockStart.gif" align=top><IMG id=Codehighlighter1_131_190_Closed_Image style="DISPLAY: none" onclick="this.style.display='none'; Codehighlighter1_131_190_Closed_Text.style.display='none'; Codehighlighter1_131_190_Open_Image.style.display='inline'; Codehighlighter1_131_190_Open_Text.style.display='inline';" src="http://www.blogjava.net/images/OutliningIndicators/ContractedSubBlock.gif" align=top>&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">public</SPAN><SPAN style="COLOR: #000000">&nbsp;Object&nbsp;execite()&nbsp;</SPAN><SPAN id=Codehighlighter1_131_190_Closed_Text style="BORDER-RIGHT: #808080 1px solid; BORDER-TOP: #808080 1px solid; DISPLAY: none; BORDER-LEFT: #808080 1px solid; BORDER-BOTTOM: #808080 1px solid; BACKGROUND-COLOR: #ffffff"><IMG src="http://www.blogjava.net/images/dot.gif"></SPAN><SPAN id=Codehighlighter1_131_190_Open_Text><SPAN style="COLOR: #000000">{<BR></SPAN><SPAN style="COLOR: #008080">4</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System.out.println(</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">Hello</SPAN><SPAN style="COLOR: #000000">"</SPAN><SPAN style="COLOR: #000000">);<BR></SPAN><SPAN style="COLOR: #008080">5</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/InBlock.gif" align=top>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</SPAN><SPAN style="COLOR: #0000ff">return</SPAN><SPAN style="COLOR: #000000">&nbsp;</SPAN><SPAN style="COLOR: #0000ff">null</SPAN><SPAN style="COLOR: #000000">;<BR></SPAN><SPAN style="COLOR: #008080">6</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedSubBlockEnd.gif" align=top>&nbsp;&nbsp;&nbsp;}</SPAN></SPAN><SPAN style="COLOR: #000000"><BR></SPAN><SPAN style="COLOR: #008080">7</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/ExpandedBlockEnd.gif" align=top>}</SPAN></SPAN><SPAN style="COLOR: #000000">);<BR></SPAN><SPAN style="COLOR: #008080">8</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top><BR></SPAN><SPAN style="COLOR: #008080">9</SPAN><SPAN style="COLOR: #000000"><IMG src="http://www.blogjava.net/images/OutliningIndicators/None.gif" align=top></SPAN></DIV>
<P>这个看似简单的应用，却带来了两个有深刻影响的性质。</P>
<P>第一，由于if,else等结构不再是预定义的语法了，而与我们自己写的代码一样，属于莫一个类的特定消息，那么也就意味着，我们可以像ifTrue一样，定义自己的分支结构。<BR>比如<BR>&nbsp;&nbsp; aUser ifNotRegistered: [ do redirect to register page ]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ifExpired: [ do redirect to active page ]</P>
<P>在不考虑性能优化的前提下，Smalltalk认为和<BR>&nbsp;&nbsp; 4 &gt;3 ifTrue: [do something]<BR>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ifFalse: [do somthing]</P>
<P>是具有一样的语义的。并不因为Boolean属于Kernel就有什么不同。因此控制结构也属于一个可编程的因素，这就是Smalltalk的轻语法特性。</P>
<P>第二，在简单的语法和完全的面向对象语义中，构造与冯诺依曼式语言完全等价的能力（这种能力在语法上表现为赋值，分支，迭代和子程序调用），于是我们可以完全用一致的面向对象的方法来构造软件。</P>
<P>很长一段时间以来，我都认为面向对象方法论是在命令式的冯诺依曼式语言的基础上，通过引入类型系统然后修修补补的得到的，由于冯诺依曼语言式的语言是面向操作层面上的，只是为了更好的刻画操作计算的一个命令的序列，因此冯语言不可避免的具有不完备的语义，混乱的抽象表达以及等等一系列的问题。作为冯语言的一个大补丁的面向对象方法，我也想当然的以为他虽然有了些进步，但是基础问题上面还是不能避免的，加之面向对象缺乏一种一致的构造方法，很多时候我们不得不回归到命令式或者过程式的方法来构造系统，从而破坏掉一种一致清晰的思路，在过程和对象之间不住地权衡（比如Domain Model之争），这个让人非常的不爽。在尝试了一些面向对象语言之后（我是在95年接触C++的时候开始了解面向对象的，而后主要使用Java做为开发语言），我发现这个问题是很难避免，于是我断言这是面向对象技术本身的问题，现在看来不过自己所学有限，没有真正用过纯面向对象语言而已，汗颜得很啊。这里向面向对象方法道个歉，嘿嘿。</P><img src ="http://www.blogjava.net/raimundox/aggbug/22986.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/raimundox/" target="_blank">Raimundox</a> 2005-12-08 15:11 <a href="http://www.blogjava.net/raimundox/archive/2005/12/08/22986.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>