??xml version="1.0" encoding="utf-8" standalone="yes"?>免费在线国产,在线综合+亚洲+欧美中文字幕,久久超级碰视频http://www.aygfsteel.com/raimundox/category/5762.html知天之所为,知h之所,至矣。知天之所,天而生也;知h之所,以其知之所知以d知之所不知Q终其天q而不中道夭者:是知之盛也?/description>zh-cnTue, 20 Apr 2010 10:10:13 GMTTue, 20 Apr 2010 10:10:13 GMT60Misquotationhttp://www.aygfsteel.com/raimundox/archive/2007/11/28/163761.htmlRaimundoxRaimundoxWed, 28 Nov 2007 10:08:00 GMThttp://www.aygfsteel.com/raimundox/archive/2007/11/28/163761.htmlhttp://www.aygfsteel.com/raimundox/comments/163761.htmlhttp://www.aygfsteel.com/raimundox/archive/2007/11/28/163761.html#Feedback1http://www.aygfsteel.com/raimundox/comments/commentRss/163761.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/163761.html被中国h误传了数千年的七句话》,颇有些哭W不得的感慨Q?br />
1. q些话的是被误传了不假Q但是最多也׃癑ֹ吧。中国知识分子不d书五l史子集的坏风气大抵是开始于所谓的新文化运动吧。再往前的人,对于q些典籍字字爬梳Q提了上句马上背下句Q就是以章句式解读Z的宋元,也不应该随随便便p忽悠了,更不用说反对宋儒理学讲究正本清源的明清了?br />
2. 古h断章取义是一U风雅的a谈习惯,所?#8220;雅言”是要字字出典的,有点像对暗号。比如我们家猫跑了,搁古代我肯定?#8220;谁之q欤Q?#8221;Q十有八九会回答_“a是典守者之q也”Q这句射的是“虎兕Z?#8221;Q正好应景。甚至ؓ了诙谐应景,故意曲解文义的情况也是很常见的。如果以此ؓ证说误传的话Q恐怕只能算是牛嚼牡丹了。顺便多说一句,其实q个毛病CZ有,不过不再是古文了Q大多数是电q视台词:“I气在颤抖仿佛天I在燃烧。是啊,暴风雨就要来?#8221;Q?#8220;道哥Q牌子啊”Q?#8220;你看我的pQ有没有长进”之类的,虽不复古韵,但也q算有趣?br />

P.S. : 今天team里有人把David Wheeler的名aQ脓在了Quote Wall上:“Any problem in computer science can be solved with another layer of indirection.”

q到的确是一句被误传的名a吧,原文?#8220;Any problem in computer science can be solved with another layer of indirection. But that usually will create another problem.


Raimundox 2007-11-28 18:08 发表评论
]]>
Feng Shui for Standard ML Programmershttp://www.aygfsteel.com/raimundox/archive/2007/07/10/129436.htmlRaimundoxRaimundoxTue, 10 Jul 2007 13:53:00 GMThttp://www.aygfsteel.com/raimundox/archive/2007/07/10/129436.htmlhttp://www.aygfsteel.com/raimundox/comments/129436.htmlhttp://www.aygfsteel.com/raimundox/archive/2007/07/10/129436.html#Feedback4http://www.aygfsteel.com/raimundox/comments/commentRss/129436.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/129436.htmlhttp://www.dcs.ed.ac.uk/home/stg/fengshui.ps.gz

今天早上打开Google Readerq见这么一,内容倒也|了Q不q是bad smell的另一个名字而已Q硬要扯上分水也只能是勉勉强强。不q郁L是,竟然是个zh的手W,国学不昌实不能不令我辈心忧啊?br>
p.s. 预计未来6个月口头:"你这写当心坏了项目的风水"


Raimundox 2007-07-10 21:53 发表评论
]]>
The Keyword 'end' Drives Me Crazyhttp://www.aygfsteel.com/raimundox/archive/2007/05/11/116864.htmlRaimundoxRaimundoxFri, 11 May 2007 12:32:00 GMThttp://www.aygfsteel.com/raimundox/archive/2007/05/11/116864.htmlhttp://www.aygfsteel.com/raimundox/comments/116864.htmlhttp://www.aygfsteel.com/raimundox/archive/2007/05/11/116864.html#Feedback1http://www.aygfsteel.com/raimundox/comments/commentRss/116864.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/116864.html
1 while @productions.inject(false) {|c, p| c |= !nullable?(p.nonterminal) && p.symbols.all? {|s| nullable? s} && @nullables << p.nonterminal}

注意1不是行号...q句用的statement modifier, 1是我能想到的最ruby语句?..

p.s.
我现在已l恢复到OO保护模式?..刚才q求短小q了头的同时Q发Cruby bulid-in object的一个陷?..
a = Array.new 5, []
[[],[],[],[],[]]
a[0] << 1
[[1],[1],[1],[1],[1]]

想不到华丽的Array直接假设传进ȝ都是值对象了Q好Ҏ也调个dup?..




Raimundox 2007-05-11 20:32 发表评论
]]>
Church Numberhttp://www.aygfsteel.com/raimundox/archive/2006/10/09/73931.htmlRaimundoxRaimundoxSun, 08 Oct 2006 18:32:00 GMThttp://www.aygfsteel.com/raimundox/archive/2006/10/09/73931.htmlhttp://www.aygfsteel.com/raimundox/comments/73931.htmlhttp://www.aygfsteel.com/raimundox/archive/2006/10/09/73931.html#Feedback2http://www.aygfsteel.com/raimundox/comments/commentRss/73931.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/73931.html
每个Church number都是一个接受两个参数的函数Q这两个参数又都是函敎ͼW一个参数称为后l函敎ͼW二个参数则叫做零点函数。依据这两个函数Q我们可以定义Church number zero, one, twoQ?br />
(define zero  (lambda (successor zero) zero))
(define one Qlambda (successor zero) (successor zero)))
(define two   (lambda (successor zero) (successor (successor zero))))

可以看出Q所谓one是寚w点函数应用一ơ后l函敎ͼ而two则是寚w点函数应用后l函数的l果再次应用后函数Q依ơ类推可以得到Church Number n。下面我们可以通过后函数increase和零点函数f(x) = 0来看看这些Church Number的计结果:

(define (increase x) (+ x 1))

(zero increase 0)
> 0
(one increase 0)
>1
(two increase 0)
>2

an approximate Java version:

public interface Function<T> {
    T apply(Object... parameters);
}

public interface ChurchNumber {
    Integer apply(Function<Integer> successor, Function<Integer> zero);
}

ChurchNumber zero = new ChurchNumber() {
   public Integer apply(Function<Integer> successor,  Function<Integer> zero) {
      return zero.apply();
   }
};

ChurchNumber one = new ChurchNumber() {
   public Integer apply(Function<Integer> successor, Function<Integer> zero) {
      return successor.apply(zero);
   }
};

ChurchNumber two = new ChurchNumber() {
   public Integer apply(Function<Integer> successor, Function<Integer> zero) {
      return successor.apply(successor.apply(zero));
   }
};

Function increase = new Function<Integer>() {
 public Integer apply(Object... parameters) {
   if (parameters[0] instanceof Function) {
      return ((Function<Integer>) parameters[0]).apply() + 1;
   }
   return (Integer) parameters[0] + 1;
 }
};

Function numberZero = new Function<Integer>() {
   public Integer apply(Object... parameters) { return 0;}
};


System.out.println(zero.apply(increase, numberZero));
>0
System.out.println(one.apply(increase, numberZero));
>1
System.out.println(two.apply(increase, numberZero));
>2

定义了Church number后,我们l箋定义Church number上的q算Q首先是增加1Q?br />
(define (inc x) (lambda (successor zero) (successor (x successor zero))))

(define three (inc two))
(three increase 0)
>3

an approximate Java version:

static ChurchNumber inc(final ChurchNumber churchNumber) {
   return new ChurchNumber() {
      public Integer apply(Function<Integer> successor, Function<Integer> zero) {
         return successor.apply(churchNumber.apply(successor, zero));
       }
   };
}

ChurchNumber three = inc(two);
System.out.println(three.apply(increase, numberZero));
>3

然后是加法:

(define (add x y) (lambda (successor zero)  (x successor (y successor zero))))

(define five (add three two))
(five increase 0)
>5

an approximate Java version:

static ChurchNumber add(final ChurchNumber x, final ChurchNumber y) {
        return new ChurchNumber() {
            public Integer apply(final Function<Integer> successor,
                    final Function<Integer> zero) {
                return x.apply(successor, new Function<Integer>() {
                    public Integer apply(Object... parameters) {
                        return y.apply(successor, zero);
                    }
                });
            }
        };
}

ChurchNumber five = add(two, three);
System.out.println(five.apply(increase, numberZero));
>5

最后是乘法Q?br />
(define (multiply x y) (lambda (successor zero)  (x  (lambda (z) (y successor z)) zero)))

(define four (multiply two two))
(four increase 0)
>4

an approximate Java version:

static ChurchNumber multiply(final ChurchNumber x, final ChurchNumber y) {
        return new ChurchNumber() {
            public Integer apply(final Function<Integer> successor,
                    Function<Integer> zero) {
                return x.apply(new Function<Integer>() {
                    public Integer apply(final Object... parameters) {
                        return y.apply(successor, new Function<Integer>() {
                            public Integer apply(Object... ignoredParameters) {
                                if (parameters[0] instanceof Function) {
                                    return ((Function<Integer>) parameters[0]).apply();
                                }
                                return (Integer) parameters[0];
                            }
                        });
                    }
                }, zero);
            }
        };
}

ChurchNumber four = multiply(two, two);
System.out.println(four.apply(increase, numberZero));

没有减法和除法,Church当年发明q套东西的时候就没有。原因是非常明显?..因此Church number只有后函数Q而没有前驱函数。也是说Church number只能往前数...不能望后?..自然不可能作出减法和除法了。当然扩展一下也是非常容易的Q?br />
(define negative-one (lambda (successor precursor zero) (precursor zero)))
(define one (lambda (successor precursor zero) (successor zero)))

(define (add x y) (lambda (successor precursor zero) (x successor precursor ( y successor precursor zero) )))

(define (inc x) (
+ x 1))
(define (dec x) (
- x 1))

(define zero (add one negative
-one))

(zero inc dec 
0)
>0


whl同学问这栯不能实现点Q答案是可以实现有限_ֺ的QҎ....因ؓ按照q个思\发展下去Q我们定义Q点的successor和precursor函数只能在有限的位数之内...当然有了one,zero再结合pairQ模?/1存储实现点也不是不可能的事?..

Raimundox 2006-10-09 02:32 发表评论
]]>
Selenium Better Praticehttp://www.aygfsteel.com/raimundox/archive/2006/08/04/61860.htmlRaimundoxRaimundoxFri, 04 Aug 2006 13:59:00 GMThttp://www.aygfsteel.com/raimundox/archive/2006/08/04/61860.htmlhttp://www.aygfsteel.com/raimundox/comments/61860.htmlhttp://www.aygfsteel.com/raimundox/archive/2006/08/04/61860.html#Feedback11http://www.aygfsteel.com/raimundox/comments/commentRss/61860.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/61860.html1. Never use Selenium FIT mode

Selenium分ؓ两种q行模式QDriven Mode(现在叫Selenium Remote Control)和FIT Mode(现在叫Selenium Core)?/p>

FIT Mode֐思义Q就是类似FIT Testing Framework那种使用方式Q主要用于QA{非技术h员编写Web应用的功能测试。FIT Mode的Selenium试使用HTML来组l测试用例。例如我要测试一个web应用的登陆功能。我可能写出q样的HTML 表格?/p>

 1 < table >
 2 < tr >
 3   < td > open </ td >
 4          < td > http://localhost:8080/login </ td >
 5          < td ></ td >
 6 </ tr >
 7 < tr >
 8   < td > type </ td >
 9          < td > id=username </ td >
10          < td > someuser </ td >
11 </ tr >
12 < tr >
13   < td > type </ td >
14          < td > id=password </ td >
15          < td > password </ td >
16 </ tr >
17 < tr >
18   < td > click </ td >
19          < td > id=login_button </ td >
20          < td ></ td >
21 </ tr >
22 < tr >
23   < td > assertTextPresent </ td >
24          < td > Welcome to xxxx </ td >
25          < td ></ td >
26 </ tr >
27 </ table >

不同于FITQSelenium内置了一pd的命令,如上例中的open, type, click以及assertTextPresentQ因此QA可以完全抛开DEV独立地编写测?FIT需要DEV提供Behavior Fixture)。因此FIT Mode是相当容易用的Q哪怕不会用HTML的QAQ也可以使用FrontPaged三列表格Q依ơ填入数据?/p>

然而对于大多数team而言——尤其是敏捷teamQFIT Modeqx的外表下是o人恐惧的泥沼。大多数团队往往选择使用Selenium作ؓ功能试和集成测试工兯不仅仅是QA试工具Q在不同的P代间遇到功能程或UI变化Ӟ必须要重构Selenium试Q或者说QFunctional Test Migration。o人遗憄是,HTML based的Selenium FIT Testing的重构竟然o人难以置信的困难。我们可以用include{Selenium FIT扩展Q得它可以重用详细的功能(Log inQ?Log out诸如此类Q。即便如此,在一个真实的目中,Selenium Test的数量往往?00-500之间(我目前所处的目在改用Driven Mode前已?50+)Q对于这么大基数的Selenium试Q手工重构几乎是不可惌的,而目前尚没有HTML代码重构工具。即便存在泛泛意义上的HTML重构工具Q对于Selenium试重构的有效性尚待商榗而用Driven Mode上述代码可以写ؓ:

1 public   void  testShouldShowAWeclomeMessageAfterUserLoggedIn()  {
2     selenium.open( " http://localhost:8080/login " );
3     selenium.type( " id=username " , " someuser " );
4     selenium.type( " id=password " " password " );
5     selenium.click( " id=login_button " );
6     assertTrue(selenium.isTextPresent( " Welcome to xxxx " ));
7 }


很自Ӟ一个训l有素的E序员会重构出如下代?

 1 public   void  login(String username, String password)  {
 2     selenium.open( " http://localhost:8080/login " );
 3     selenium.type( " id=username " ,username);
 4     selenium.type( " id=password " , password);
 5     selenium.click( " id=login_button " ); 
 6 }

 7
 8 public   void  testShouldShowAWeclomeMessageAfterUserLoggedIn()  {
 9     login( " someuser " " password " );
10     assertTrue(selenium.isTextPresent( " Welcome to xxxx " ));
11 }

之后无论是pull up到公共基c还是extact到Utils class都是很容易的事情。由于Java在代码重构上便利QJava Selenium Remote Control成ؓ使用Selenium的最x式。在q一点上Q纵使Ruby语法上比Java单灵zd多,它仍不是~写Selenium试的最佌?当然一个经q精心设计的ruby selenium dsl wrapperq是h非凡的h值的Q这个我们后面会涉及??/p>

2. Using the name user, system, page instead of selenium

观察上面提到的代码,其中使用selenium来操Uweb应用的行为,q在Remote Control里是常见的做法,但是仍然不够好,我们可以做一些小的变化以得到更好的测?

 1 protected   void  setup()  {
 2     selenium  =    //  intialize selenium instance
 3     user  =  selenium;
 4     currentPage  =  selenium;
 5 }

 6
 7 public   void  login(String username, String password)  {
 8     user.open( " http://localhost:8080/login " );
 9     user.type( " id=username " ,username);
10     user.type( " id=password " , password);
11     user.click( " id=login_button " ); 
12 }

13
14 public   void  testShouldShowAWeclomeMessageAfterUserLoggedIn()  {
15     login( " some guy " " password " );
16     assertTrue(currentPage.isTextPresent( " Welcome to xxxx " ));
17 }

基本上这只不q是"另一U写?而已Q但是它更好的表达了"用户的行?Q如login代码所C。以?pȝ的正相?Q即currentPage.isTextPresent()。这U是典型的对~译器无意义对h有意义的代码Q也是普遍意义上好的代码?/p>

3. Creating a DSL base on your test codes

懂得HTML的QA可以在没有DEV的帮助下使用Selenium FIT modeQ然而却不能在没有DEV的帮助下使用Driven Mode。于是最自然也是最fashion的做法,是在已有的test codes之上提供Testing DSL或者Scripting LanguageQ让FIT mode变得更加FIT。这斚w内容是一个更大的主题Q以后再详细展开吧?/p>

4. Hacking Selenium Object to support FIT command

Selenium FIT mode和RC mode下的命o有些许差异,比如FIT中的assertTextPresentQ在RC中变成了isTextPresent。同栯有FIT中最实用的命令clickAndWaitQ在RC中变成了click和waitForPageToLoad。在RC中用FIT mode中的命o也非难事Q找到com.thoughtworks.selenium.SeleniumQ添加方?

public   void  doCommand(String commmand, String parameters);

然后在com.thoughtworks.selenium.DefaultSelenium中添加实?

1 public   void  doCommand(String commmand, String parameters)  {
2    String[] paras  =   new  String[] { "" , "" , "" }
3     for  ( int  i  =   0 ; i  <  parameters.length  &&  i  <   3 ; i ++ )
4       paras[i]  =  parameters[i];
5    commandProcessor.doCommand(command, paras);
6 }

然后试验一?

selenium.doCommand( " clickAndWait " );

在我们用纯RC mode之前曄用过一D中间方案,rc code转化为fit code来跑(因ؓrc不支持https)Q由于不是真正的rc modeQ像isTextPresent之类的方法都没有办法使用Q只能用FIT mode command。因此如果因Z些特D的原因(https, chrome起不来,hta bug多等{?Q你没有办法使用RC modeQ但是有希望得到RC可重构的好处Q那么这个tricky的技巧倒是不错的选择?/p>

5. Using chrome and IE hta lanucher to support https
6. Run test using different browser lanucher to test browser compatibility

q两个都是和browser lanucher相关的,Selenium和JWebUnit最大的不同在于它用真实的览器来跑测试,从而可以更加真实地考察pȝ在不同浏览器中的表现。因此用不同的览器lanucher来运行测试,可以更好试应用的浏览器兼容性,q对于web 2.0应用而言是很有帮助的。此外,使用rc提供的试验性lanucherQchrome和hta可以解决跨domain试和https的问题。不q目前htaq是有很多bug的,推荐使用chrome。当Ӟ最希望的还是澳z的同事可以早日在selenium里提供https支持?br />



Raimundox 2006-08-04 21:59 发表评论
]]>
ANTLR Lexer Tipshttp://www.aygfsteel.com/raimundox/archive/2006/03/27/37605.htmlRaimundoxRaimundoxMon, 27 Mar 2006 06:44:00 GMThttp://www.aygfsteel.com/raimundox/archive/2006/03/27/37605.htmlhttp://www.aygfsteel.com/raimundox/comments/37605.htmlhttp://www.aygfsteel.com/raimundox/archive/2006/03/27/37605.html#Feedback4http://www.aygfsteel.com/raimundox/comments/commentRss/37605.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/37605.html阅读全文

Raimundox 2006-03-27 14:44 发表评论
]]>
A Patch for Ruby Watir Test Frameworkhttp://www.aygfsteel.com/raimundox/archive/2006/01/11/27549.htmlRaimundoxRaimundoxWed, 11 Jan 2006 03:30:00 GMThttp://www.aygfsteel.com/raimundox/archive/2006/01/11/27549.htmlhttp://www.aygfsteel.com/raimundox/comments/27549.htmlhttp://www.aygfsteel.com/raimundox/archive/2006/01/11/27549.html#Feedback2http://www.aygfsteel.com/raimundox/comments/commentRss/27549.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/27549.html
Beauty is the first test: there is no permanent place in this world for ugly mathematics.

感动了我好久。现在换个说法:

Beauty is the first test: there is no permanent place in this world for ugly hack code.

q个问题也不太难出理Qruby作ؓC的front interface在字W串处理上有很深的C的痕q,嗯,10q前我还是个CE序员嘛Q按照从前的做法区分ASCII码?br>
1 def characters_in(value) 
2   index = 0
3   while index < value.length 
4     len = value[index] > 128 ? 2 : 1
5     yield value[index, len]
6     index += len
7   end 
8 end

把TextField里的doKeyPress改一下:

1 characters_in(value) {|c| 
2   sleep @ieController.typingspeed
3   @o.value = @o.value.to_s + c
4   fire_key_events}

搞定Q但是还是很丑,直接把别人的code改了Qcontributing to eclipse里说要contribute不要随便change别h的代码。好吧,好在ruby扩展h也不难:

 1 require 'Watir'
 2 
 3 module Watir
 4   module Cn
 5     class IE <Watir::IE
 6       def text_field(how , what=nil)
 7         return TextField.new(self, how, what)
 8       end
 9     end
10     
11     class TextField < Watir::TextField
12       def doKeyPress( value )
13         begin
14           maxLength = @o.maxLength
15           if value.length > maxLength
16             value = suppliedValue[0 .. maxLength ]
17             @ieController.log " Supplied string is #{suppliedValue.length} chars, which exceeds the max length (#{maxLength}) of the field. Using value: #{value}"
18           end
19         rescue
20           # probably a text area - so it doesnt have a max Length
21           maxLength = -1
22          end
23                        
24         Cn.characters_in(value) {|c| 
25           sleep @ieController.typingspeed
26           @o.value = @o.value.to_s + c
27           fire_key_events}
28       end
29     end
30     
31     def Cn.characters_in(value) 
32       index = 0
33       while index < value.length 
34         len = value[index] > 128 ? 2 : 1
35         yield value[index, len]
36         index += len
37       end 
38     end
39   end
40 end

试一下:

require 'watir-cn'

ie 
= Watir::Cn::IE.start('http://www.google.com')
ie.text_field(:name, 
'q').set('Ruby Watir 功能试'

成功。最后一步是贡献C֌Q直接登到rubyforgeQ找到Watir然后submit了两个patchQ一个直接修改watir库的一个是独立的watir-cn的。推荐大家用第二个的patch。地址在:http://rubyforge.org/tracker/index.php?func=detail&aid=3232&group_id=104&atid=489


Raimundox 2006-01-11 11:30 发表评论
]]>
A Day of Two Pragmatic Programmers' Lifehttp://www.aygfsteel.com/raimundox/archive/2006/01/10/27469.htmlRaimundoxRaimundoxTue, 10 Jan 2006 13:30:00 GMThttp://www.aygfsteel.com/raimundox/archive/2006/01/10/27469.htmlhttp://www.aygfsteel.com/raimundox/comments/27469.htmlhttp://www.aygfsteel.com/raimundox/archive/2006/01/10/27469.html#Feedback9http://www.aygfsteel.com/raimundox/comments/commentRss/27469.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/27469.html解决q个问题最直接的做法,是login到SSOq_上,然后一个用户一个用LsearchQsearch完了再用OA Admin登陆查OA帐户。我们是pragmatic programmer嘛,q么J琐的活动自然写E序搞定它。自然QC个选择QRuby WatriQ还有就是自俺们公司的Selenium Script?BR>上来先用Ruby WatriQ这个东西好啊,单啊。WPC找了一个以前写的example, 我照着改了一个用LsearchQ然后扩展:
 1 # login in as sso admin
 2 ie = Watir::IE.start(sso_login_url)
 3 ie.text_field(:name,"username").set(sso_admin_user)
 4 ie.text_field(:name,"password").set(sso_admin_pass)
 5 ie.button(:value, "d").click
 6 
 7 # search user
 8 ie = Watir::IE.start(sso_search_url)
 9 ie.text_field(:name, "userName).set('张三')
10 ie.button(:value, "查找").click

跑到command line run一把,ruby login.rbQ然后一个古怪的事情出现?BR>
ie.text_field(:name, "userName).set('张三')
userName输入框highlight了一下,然后没有?..N是编码问题?换了encoding重新save了一把,l果一栗郁?..于是我和WPCx?..Ruby中文有问题,不管了时间紧q,换Selenium TestQ自家的东西嘛。但是Selenium的Script是HTML-based的,写v来太ȝ。我们是pragmatic programmer嘛,q么J琐的活动自然写E序搞定它。于是我来搞一个ScriptGeneratorQWPC同志搞script template。一搞template WPC同志比较兴奋,大喊:velocityQ?velocityQ哎Q我机器上没有velocity的libraryQ于是我军_pragmatic一把,直接writer output。找了一个Selenume Script DemoQ在每行前面加上aaaa,每行末尾加上bbbQ然后ctrl + f,aaa->writer.write(" bbb->"); 改几?Qintroduce parameter, extract method, compose method飞快地重构之Q一个hard code的generator引擎诞生了。WPCq在调templateQ我看了一下代码,蛮ugly的,refactory之:
 1     private static String scriptTemplate;
 2 
 3     public static void readScriptTemplate(String templateName) {
 4         BufferedReader reader = null;
 5         try {
 6             reader = new BufferedReader(new FileReader(templateName));
 7             String line = null;
 8             StringBuffer template = new StringBuffer();
 9             while ((line = reader.readLine()) != null)
10                 template.append(line).append("\n");
11             scriptTemplate = template.toString();
12         } catch (IOException e) {
13 
14         } finally {
15             if (reader != null)
16                 try {
17                     reader.close();
18                 } catch (IOException e) {
19                 }
20         }
21     }
22 
23     public static void generatedScriptForUser(String path, String name) {
24         Writer writer = null;
25         try {
26             writer = new BufferedWriter(new FileWriter(path + "/" + name
27                     + ".html"));
28             writer.write(scriptTemplate
29                     .replaceAll("\\$\\$userName\\$\\$", name));
30         } catch (IOException e) {
31             e.printStackTrace();
32         } finally {
33             if (writer != null)
34                 try {
35                     writer.close();
36                 } catch (IOException e) {
37                 }
38         }
39 
40     }

一下子了无数代码Q爽多了。然后wpc也搞好了templateQ按模版文g一generatingQ几十个selenium test script出C。嗯Qwrite program that write programQ有够pragmatic?BR>
写了一个Test SuiteQ放到改一下Selenium Runner下跑一下又ȝ了。Selenium做的Functional TestQ一般假定和被测的应用在一个URL base里,因此q样local“测”remoting׃太好Q而且我们又是一个安全^収ͼURL base做安全基准的。一下就所有测试就crackdown在这里了。郁闷啊...
Selenium文档Q发现可以用driver来adpater local和remoting的环境,问题是这个drvier要自己写...郁闷...
WPC在firefox上装了一个Selenium Recorder的plug in可以记录web page actionsQ然后replay。他发现q个东西能绕qSelenium的限Ӟ于是军_看看他怎么实现的,扑ֈcode一?..原来是把selenium runner hack?..用javascript把url base生生的给改了...WPC说好啊,我们写一个Firefox Selenium Recorder Plugin的plug in吧,让他从一个目录里自动load script...然后WPC开始玩firefox plugin.

我决得我q是看看Ruby的中文支持吧Q找来找去都没有说Ruby的中文有问题的,后来发现一个老大了一下Ruby的中文字W串Q说没问题。我忘了q个老大的URL了找到再补上。代码上看v来似乎也没什么问题。于是我怀疑是Watri的问题,看Watri的代码,发现Watri的设计思\是Z模拟人的录入Q然后找到这L代码Q?BR>
def doKeyPress(value)



for i in 0 .. value.length-1   
   sleep @ieController.typingspeed   # typing speed
   c 
= value[i,1]
   #@ieController.log  
" adding c.chr " + c  #.chr.to_s
   @o.value 
= @o.value.to_s + c   #c.chr
   fire_key_events
end



end
Ҏ讑֮的g时模拟h敲击键盘。每一个间隔用String slice来输入。于是我试验了一下ruby的中文字W串切片Q?BR>
1 value = "哈哈"
2 for i in 0..value.length-1 
3   puts value[i,1]
4 end
Ruby果然瞎菜?..value.length?Q每一个切片都是空...啊~~~~天啊Q?bit char...C的时代啊。找C问题好办了Q我权衡了fix watri unicode和直接hack它,最后我选择直接hack它,Ҏ单:

 1 if @ieController.typingspeed != -1            
 2   for i in 0 .. value.length-1   
 3   sleep @ieController.typingspeed   # typing speed
 4   c = value[i,1]
 5   #@ieController.log  " adding c.chr " + c  #.chr.to_s
 6   @o.value = @o.value.to_s + c   #c.chr
 7   fire_key_events
 8   end
 9 else
10   @o.value = value
11   fire_key_events
12 end

然后试一下:
1 require 'Watir'
2 
3 ie = Watir::IE.start("http://www.google.com")
4 ie.typingspeed = -1
5 ie.text_field(:name, "q").set("哈哈")

搞定。于是准备改Ruby脚本Q这个时候客户下班了Q我们决定明天l,一q?时...

最后说一下需求,一共有多少数据呢?70?..如果pair录入的话Q大U?0-50分钟?BR>
l论:

1.Pragmatic Programmer都是很懒的,重复5ơ的工作都回用代码来写?BR>2.Pragmatic Programmer都是很有好奇心的Q太多的重复性劳动只能分散他们的注意力,不知道会搞出什么了Q我估计我要没有hack WatriQWPC已经开始写Firefox plugin了?BR>3.Pragmatic Programmer都是“古E序员”,写程序操U计机是很有乐的?BR>4.比一个Pragmatic Programmer更能折腾的是两个Pragmatic Programmer...




Raimundox 2006-01-10 21:30 发表评论
]]>
丧钟?(4)http://www.aygfsteel.com/raimundox/archive/2005/12/21/24957.htmlRaimundoxRaimundoxWed, 21 Dec 2005 07:51:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/21/24957.htmlhttp://www.aygfsteel.com/raimundox/comments/24957.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/21/24957.html#Feedback2http://www.aygfsteel.com/raimundox/comments/commentRss/24957.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/24957.htmlW?. 一切皆对象和面向对象的理论基础

老庄是反对一切皆对象的,而TrustNo1在javaeye的一帖子上?

W一Q我可以很负责的?OO的,70q代成型Q?0q代在理论基上就lh毙掉。从q种意义上说不是OOMȝ问题Q而是OOq活着么?当然理论基础lh毙掉Q不是说没有用?/SPAN>

我先说面向对象的理论基础的问题,至于一切皆对象E后再表?BR>
所谓面向对象的理论基础其实是没有的Q原因很单,面向对象Ҏ׃是一U计模型。在W一ơY件危机的那个时代Q对与计机的非数D应用的讨论以及对于可计性问题的研究和发展,大抵立了几U主的计算模型Q递归函数c,囄机,Lambda演算QHorn子句QPostpȝ{等?BR>
其中递归函数cL可计性问题的数学解释;囄机是囄解决可计问题的时候所设计的装|,其后成ؓ计算机的装置模型Q与囄机相关的形式语言和自动机成ؓ了命令式语言的理论基;lambda演算成ؓ了函数式语言的理论基;Horn子句是prologq类逻辑语言的理论基。但是我们惊讶的发现Q面向对象没有计模型的理论基础Q换而言之,面向对象Ҏ׃是从可计性的研究上发展过来的Q那么面向对象的理论基础的h值本w就不大?/P>

所以我很奇怪的一个问题就是TrustNo1所谓的面向对象?0q代理论基础上给人毙掉的说法是从何而来的?既然面向对象本质上不是一U计模型,那么它大抵上只能归结ZU应用技术,应用技术自然可以从各种不同的领域里得到怼的应用,那么毙掉的理论基所指的又是什么呢Q甚怪之?/P>

既然面向对象不是一个计模型,那么我们可以从不同的角度推断出OO的各UŞ态,老庄已经出给了从ADT引出OO的问题以及例子,我就不罗嗦了Q我l一个从Functional Programming出来的例子,其实是SICP里的Data as Procedure?/P>

(define (make-user name age sex)
  (define (dispatch message)
     (cond ((eq
? message 'getName) name)
           ((eq? message 'getAge) age)
           ((eq? message 'getSex) sex))
           (else (error 'messageNotUnderstand))))
  dispatch)

然后我们可?/P>

(define vincent (make-user 'Vincent 24 'Male))
(vincent 
'getName)

自然的,如果我调?/P>

(vincent 'sayHi)

会得C个messageNotUnderstand的runtime错误Q这是一个很自然dyanmic type的对象封装,最早的面向对象pȝSmalltalk和CLOS基本上都是这个\子,于是有一个问题,Z么最早的面向对象pȝ都是dyanmic typeQ这里就跟lambda演算有关了?/P>

lambda演算q个计算模型Ҏ的一个假讑ְ是,对于M一个定义良好的数学函数Q我都可以用lambda抽象来表qC的求|因此无论是什么东西你能够构造lambda抽象的话Q我p计算。这个地方东西很多,大家可以找找lambda演算相关的资料,q里我说三g?׃lambda太难输入Q我用schemeE序代替Q然后由于alpha变化Qbeta规约和eta规约我也用scheme伪码来模拟?

W一个是数值的表述Q其实这个很单,不考虑丘奇代数的系l的话,我们可以把数DC成单值函?

(define one (lambda (x) 1))

q个东西无论l什么x都返?Q然后根据lambda演算里的alpha变换Q这个lambda抽象{h于数?。因此,对于所有的数|我们可以按lambda演算处理?/P>

W二个是bool的表达,也就是如何逻辑q行lambda抽象Q下面我直接l出了,~省认ؓ大家都看了SICPQ对Scheme也颇有心得?/P>

(define true-new (lambda (x y) x)) ;;;q个函数也叫select-first
(define 
false-new (lambda (x y) x));;;q个函数也叫select-second

(define 
if-new (lambda (conditon if-true if-false) (condition if-true if-false)))

然后我就可以做一个测?/P>

(if-new true-new 3 4)
3

(
if-new false-new 3 4)
4

因此Q对于所有bool我们可以按lambda演算来处?/P>

W三个是自定义类型,q里我们q是先看一个Lisp里的例子Q序寏V?/P>

(define (cons a b) (lambda (dispath) (dispatch a b)))
(define (car list) (list select
-first))
(define (cdr list) (list select
-second))

q里依旧是high-orderQ我们来试

(define list1 (cons 1 2))
(car list1)
1
(cdr list1)
2

q里大家自己用beta规约一下,发现的是q样的。这里我们又可以看到Q在lambda演算里,Ҏ没有数据或者类型。有的永q各U各Llambda抽象而已(目前已经有了带类型的lambda演算)。这里说一句题外话QSICP里的Data as Procedure其实是在说q个问题Q不q他没明_而是用了一U特D的用法而引Z消息传递风|我觉得这里SICP有些此失彼Q对于data as procedure我ȝ的一般Ş式是

(define (construct-function value1 value2 value3 value4valuen) (lambda (dispatch) (dispatch value1 value2 value3 value4valuen)))
(define (select
-function1 data) (data select-first))
(define (select
-function2 data) (data select-second))
.
(define (select
-functionn data) (data select-last))

lg所qͼ我们看到在lambda演算里,一切都是lambda抽象Q然后对于不同的lambda抽象使用alpha变换Qbeta规约和eta规约Q表q各U不同计。看Q在面向对象之前已l有了一切皆某某的完的计算理论存在了。而且回顾一下:

(define (make-user name age sex)
  (define (dispatch message)
     (cond ((eq
? message 'getName) name)
           ((eq? message 'getAge) age)
           ((eq? message 'getSex) sex))
           (else (error 'messageNotUnderstand))))
  dispatch)

(define vincent (make
-user 'Vincent 24 'Male))
(vincent 
'getName)

我们有理pQ对象其实就是一个lambda抽象Q所以一切皆对象不过是一切皆lambda抽象的演化,q也是ؓ什么SICP里把面向对象UC一U“方便的界面”而不是一U抽象的Ҏ的原因了。那么对象和lambda抽象又什么区别呢Q?BR>
嘿嘿Q熟悉FP的h都应该知道了Q就是Side-EffectQ副作用。对象允许对其内部状态进行修改,那么q个东西q化了eta规约的前提条Ӟ也就是说允许修改内部状态的东西Q已l不是一个可以进行lambda计算的lambda抽象了。因此暂且给一个别的名字吧Q就叫对象吧.....因此我认为,对象很大E度上是一U带有副作用的lambda抽象?/P>

我在有一blog上写了Say sorry to object-orientedQ里面给了一只用对象作分支的例子Q这里就不重复了Q有兴趣大家可以ȝ一下(刚才好像在JavaEye上看C个说法,说Everything is Object是Smalltalk的广告语Q唉QSmalltalk里的的的确everything is object啊。)

q里我们来ȝ一下,面向对象作ؓ一U“方便的界面”主要解决了一个局部化和模块化的问题,q是从lambda演算和函数编E的角度来看面向对象技术。(taowen在他的一blog上说Q面向对象局部化了Side-EffectQ我׃为然Q,q个东西我个为更加接q面向对象本来的意思,而不是由ADT里发展出来的带类型的对象pȝ的那个意思。因此老庄不以为然的面向对象类型系l,我也不以为然。但是面向对象作为lambda抽象的界面,我觉得还是很不错的。这一点在Smalltalk和Ruby里都有不错的体现?/P>

Raimundox 2005-12-21 15:51 发表评论
]]>
丧钟鸣?(3)http://www.aygfsteel.com/raimundox/archive/2005/12/21/24891.htmlRaimundoxRaimundoxTue, 20 Dec 2005 16:44:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/21/24891.htmlhttp://www.aygfsteel.com/raimundox/comments/24891.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/21/24891.html#Feedback1http://www.aygfsteel.com/raimundox/comments/commentRss/24891.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/24891.htmlW? l承

前面已经说过了,l承臛_?个语? 实现l承和类型承,在说明这两个东西之前Q我们l来看上面的例子

Person>>playSoloOnInstrument:instrument
  instrument playNote: Note C;
             playNote: Note D;
             playNote: Note E.

Person
>>playBackgroundOnInstrument:instrument
  instrument playChord: Chord C1;
      playChord: Chord C1;
             playChord: Chord C1;

Person
>>playBWV996OnInstrument:instrument
   instrument playNote: Note C;
              playChord: Chord C;
              playNote: Note D.

现在我们看playBWV996q个消息QBWV996是Bach所写一个鲁特琴l曲Q鲁特琴是弹拨乐器,同时也是和声乐器(所谓和C器就是可以演奏和?。在很多乐器上都有改~的版本Q比如鲁特琴的近亲吉他等{,q个时候,我们可以实现q样几个c?/P>

Lute>>playNote:note
  
Lute
>>playChord:note
  

Guitar
>>playNote:note
  
Guitar
>>playChord:note
  

Bass
>>playNote:note
  

然后我们可以试以此调用

vincent.playBWV996OnInstrument: Guitar new.
vincent.playBWV996OnInstrument: Lute 
new.
vincent.playBWV996OnInstrument: Bass 
new.

最后一个会得到一个messageNotUnderstand的错误。也是_对于Bass而言׃不能演奏和声从而不能演奏BMV996(不过q个世界上能人太多了...?Q我们换到静态类型面向对象系l来看?BR>对于W一个方法,playSolo的时候我们要求的cd是能够演奏单音的。我们可以写出来

1interface SoloInstrument {
2  SoloInstrument playNote(Note note);   
3}

对于W二个方法,playChord的时候我们要求的cd是能够演奏和弦的Q我们可以写出来

1interface ChordInstrument {
2  ChordInstrument playChord(Chord note);   
3}

而对于第三个ҎQplayBWV996的时候我们要求既能演奏和弦也能演奏单韻Iq个时候出C个问题,我们怎么处理Instrument的承关p?一个能演奏和u的乐器是否可以演奏单?{案是一般而言是的Q但是也不排除有一些不是这L)?q是我们单的?

1interface SoloAndChordInstrument extends SoloInstrument, ChordInstrument{
2}

或?/P>

1interface BWV996Playable {
2
3  BWV996Playable playNote(Note note); 
4  BWV996Playable playChord(Chord note);  
5}

对于动态类型简单的隐性类型约定,昄的类型系l带来的一个副作用是我们必须处理cd之间的关pR?STRONG>注意q里是类型之间的关系Q而不是对象之间的关系。老庄同志批了很多的面向对象的抽象,面向对象的类型系l以及面向对象的本体论,其实都在是在cd关系上折腾,而不是在对象关系上折?/STRONG>。而事实上面向对象?STRONG>cdpȝq必然是静态类型系l,而我们的cM间的关系不一定就和类型的关系怸致?/STRONG>像上例所C,在Smalltalk里,LuteQGuitar和Bass之间没有M的承关p,但是对于person?个消息而言Q它们却是有cd的?BR>
因此老庄所批的Q是对象cdpȝ的抽象能力,而非面向对象的抽象能力。正如他在类型系l里所l的例子Q那张他认ؓ很失败的面向对象的图Q其实可以完全不依赖l承来实玎ͼ而对q个cdpȝ的消费者而言Q他们能够以一定的cd的观点,来处理这个系l的对象?/P>

而老庄最后一个结?

我的l论是:“一个类型,是由其本质决定了所能表现出的可操作性,而不是有其所能接受的操作军_了其本质。然而,OO正好把这个问题搞反了Q?/SPAN>

我的看法是,q句话根本就是诡辩,前面半句的主语是“一个类型”,后面半句的主语是"OO"...

虽然前半句是对的Q但是换一栯法可能更?"所能接受的操作反映了其本质"Q面向对象本w就没有说我要做一个本质抽象,q一点在Smalltalk的类型判断操作上的可能是一个佐证,Smalltalk用isKindOf来判断承关p,我们来玩一个文字游戏,Ҏ俚语是kindaQ也是"有一点,有几?的意思,而不是说Q“就是”,或者“从分类学上可证明之cȝ含义”。我再D一个龌龊的例子?/P>

vincent ballon: AirBallon new.
vincent ballon: Condom 
new.

气球和保险套Q对于ballonq个Ҏ而言是一个类型,都是"有几?可以吹v来。但是我怎么定义一个精的本质QBallonableQ还是MakeFromLatexAndVeryThin?或者简单说FlexableAndThinQ?/P>

在承这一点上Q我惌庄引文?Elminster的话是从事物的特征与属性归U_它的“类型”。恰恰对于静态类型面向对象系l是可行的。如我前文所qͼ我把一个object和所有sender的约定(也就是interfaceQ,l承在一P恰恰是一个颇为恰当的cd定义?BR>
而对于动态类型系l里的面向对象语aQ承的也有cdl承的含义,但是q不是唯一的途径。用一句我们常说的话,在静态类型系l里Q类型和cL紧耦合的,动态类型系l中他们的耦合比较松?BR>
从此而观Q所有对于面向对象的哲学考虑以及本体的思考,对于动态面向对象系l已l不是那么迫切了。而把对象cdpȝ的不_咎于面向对象的不I也似乎论据不?/P>

Raimundox 2005-12-21 00:44 发表评论
]]>
丧钟鸣?(2)http://www.aygfsteel.com/raimundox/archive/2005/12/21/24889.htmlRaimundoxRaimundoxTue, 20 Dec 2005 16:22:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/21/24889.htmlhttp://www.aygfsteel.com/raimundox/comments/24889.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/21/24889.html#Feedback2http://www.aygfsteel.com/raimundox/comments/commentRss/24889.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/24889.htmlW? 关于"接口"

关于接口的问题老庄说对了,q个东西q不属于面向对象的概念,而且在动态类型面向对象语a(比如Ruby, Smalltalk?Q根本没有这个东ѝ这是一个纯_的静态类型面向对象语a的特性,或者直接说Q接口就是一个纯cd(Type)。还是上ơ的例子Q?/P>

 1interface Instrument {
 2   void playNote(Note note);
 3   void playChord(Chord chord);
 4}

 5
 6in Person Class
 7
 8void playSolo(Instrument instrument) {
 9 
10}

在我接触Smalltalk的最开始的一D|间里Q这U地Ҏ让我最隑֏Q我已经习惯了用cd辅助我的思维Q但是我发现我在Smalltalk里做不到Q虽然我可以写出

Instrument>>playNote:note
  
^self subclassResponsibility.

Instrument
>>playChord:chord
  
^self subclassResponsibility.

但是他却不是一个接口,我可以很?/P>

instrument = Instrument new.
instrument playNote: Note C.

来构造一个Instrument之后在它之上调用playNoteҎQ然而我会得C个messageNotUnderstand的错误,Smalltalk和Ruby里没有Abstract的概c也是说abstract methodQabstract class以及interfaceQ都不是面向对象的概念(或者严g些说Q都不是面向对象的必ȝ概念Q,而是面向对象cdpȝ的概c那么在Smalltalk里我们会怎么做呢Q?/P>

Person>>playSoloOnInstrument:instrument
  instrument playNote: Note C;
             playNote: Note D;
             playNote: Note E.

Person
>>playBackgroundOnInstrument:instrument
  instrument playChord: Chord C1;
                      playChord: Chord C1;
                      playChord: Chord C1;

对于playSoloOnInstrument:instrumentQ我们对于instrument的类型是有要求的Q就是它必须能够接受playNoteq个消息。当然这个类型需要是隐性,我也可以对等的写出静态面向对象的代码把这个隐性的cd昄的表C出?

1interface Instrument {
2   Instrument playNote(Note note);  
3}

同样对于W二个方法我们也可以写出?

1interface Instrument {
2   Instrument playChord(Note note);  
3}

如果我们需要多于一个的消息也是一LQ比?/P>

Person>>playBWV996OnInstrument:instrument
   instrument playNote: Note C;
              playChord: Chord C;
              playNote: Note D.

同样q个时候隐性的cd需要就?/P>

1interface Instrument {
2   Instrument playNote(Note note);  
3   Instrument playChord(Note note);  
4}

那么接口是什么呢Q我l出一个不切的说法,interface是一个消息的发送?sender)和一个消息的接受?reciver)间的一U类型的U定Q也是说在我看来interface的用处主要在l粒度的昑ּcdU定。我有一个同事,每次写代码都Z个Test Case所要测试的对象定义一个interfaceQ每个interface都只?-3个方法(lx同学怽?DQ,q是很得interface之三味的用法。这U的做法对于在静态的面向对象pȝ的好处我们在l承里再?/P>

至于老庄所说的接口是多l承的一U代替品Q这只不q是世俗的看法,在静态类型的面向对象里,l承臛_?个语?

1.实现l承Q这个在SmalltalkQRubyQC++里有Q而在java里没有,C++里是通过private extends来实现的

1class SubClassA: private ImplementationParent {
2}

q也是C++里ؓC多的subclass不是subtype的例子?/P>

2.cdl承Q这个在C++和java里有Q而在smalltalk,ruby有却不明显?/P>

cdl承的极致就是C++里的U虚父类

1abstract class Parent {
2
3  public asbtract void method1() = 0;
4  public asbtract void method2() = 0;
5}

也就是java里的interface

1interface Parent {
2   void method1();
3   void method2();
4}

因此Q也明了了Q所谓“面向接口编E”是以类型作为约定的~程。我觉得q点大家一定不陌生Q面向接口的~程里interface都很而且U定明确。但是要说明一点的是,q个东西?面向抽象而不要面向具体编E?其实q不一P所以这个东西也׃仅能是静态类型面向对象的一个惯用法Q还C了原则这么高?/P>

Raimundox 2005-12-21 00:22 发表评论
]]>
丧钟鸣?(1)http://www.aygfsteel.com/raimundox/archive/2005/12/20/24851.htmlRaimundoxRaimundoxTue, 20 Dec 2005 11:58:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/20/24851.htmlhttp://www.aygfsteel.com/raimundox/comments/24851.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/20/24851.html#Feedback10http://www.aygfsteel.com/raimundox/comments/commentRss/24851.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/24851.html开之前先说明一下,我和老庄有着不错的私交,他最初写丧钟pd的时候,我是忠实的拥怹一Q庄兄见我尚有寸所长,q在丧钟pd里引用了我的几个观点。然而最q一D|间里Q我作了q样几g事情Q?/P>
1.重新学习了lambda演算。我的数学基不及taowen{,费了一些时日仍不完全了Ӟ目前大抵能对着R5RS后面的语义定义对一些简单的schemeE序q行lambda演算?BR>2.反复研究了几遍SICP。同时看了录像和书(感谢曹老师下的VideoQ,自信对前二章半有些许认识书中未及Q后二章半粗知大览尚不能发前人所未发之言?BR>3.学习了Smalltalk和RubyQDuck Typing以及其他一些有关类型系l的东西?BR>4.回顾了一下面向对象语a的一些发展史Q以史ؓ鉴粗知一些兴ѝ?BR>5.l日和taowenQ老庄讨论语言、设计等{之c,每ؓ一辨必Ih所知争发一aQ所以知识可以迅速杂p?D

l过U种之后Q发现当初所谓鸣OO之钟,实在是言q其实?BR>--------------------------------------------------------------------------------------------------------------------------------------------------------------
W? 关于"面向对象"

既然要ؓ人家敲钟,先要扑֯了苦主,不然岂不是白忙活了一场。什么是面向对象Q这个问题太大,我们举一个很常见的例子:

interface Instrument {
   
void playNote(Note note);
   
void playChord(Chord chord);
}


abstrat 
class Keyboard implement Instrument {
  ..
}


class ClassicGuitar implements Instrument {
   .
}


class Piano extends Keyboard {
  ..
}


in person 
class

void playSolo(Instrument instrument) {
   instrument.playNote(AbsoluteNote.C1).playNote(AbsoluteNote.C2);
   
}


void playBackground(Instrument instrument) {
   instrument.playChord(Chord.C5).playChord(Chord.C9);
   
}



in some 
case

ClassicGuitar perez711
= .
Piano pianoHere 
= .

vincent.playSolo(stenzel);
may.playBackground(pianoHere);

etc.

q个例子自然很不充分Q不q承啊Q接口啊Q多态啊Q略丑֤概,可以作Z个讨论的例子。从q个例子里,我们发现有这样一个事实,是PersoncL两个Ҏ

void playSolo(Instrument instrument);
void playBackground(Instrument instrument);

分别表示Q需要一个类型ؓInstrument的对象instrumentQ然后对他进行相应的操作Q而且Q从概念上来ԌW一个方法,使演奏旋律的Q也是单音Q而第二个Ҏ是演奏和声的。那么,如果我有一个类

class GlassBottle {

   
void playNote(Note note) {
      ..
   }

}

我们知道Q玻璃瓶装了水也是可以发出声韻IMozart可是为玻璃瓶写过曲子的,而这里我们却不能

GlassBottle beerBottle = .
vincent.playSolo(beerBottle);

因ؓ我们在构造Personcȝ时候,我们的playҎ是依赖一个类型ؓInstrument的ObjectQ换而言之,我们q里所谓的Object-Oriented其实UCObject-with-Type-Oriented的更合适,其实q类语言有一个专有名词,叫做static type object oriented。那Object-Oriented是不是就一定是Static Type Object Oriented的呢Q不Ӟ比如在Ruby里,我们可以写成Q?/P>

class Person 
  def playSolo(thing)
     thing.playNote(Note.C1).playNot(Note.c2)
  end
  def playBackground(thing)
     thing.playChord(Chord.C5).playChord(Chord.C9)
  end
end

class Guitar
  def playNote(note)
    
  end
  def playChord(chord)
    
  end
end

class GlassBottle
  def playNote(note)
    
  end
end

然后可?/P>

perez711 = Guitar.new
vincent 
= Person.new
vincent.playSolo(perez711)

同样也可?/P>

vincent.playSolo(GlassBottle.new)

在这里,cd可以推演也可以留到runtime查,如果是推演的话,在playNote里,׃thing调用了playNoteҎQ所以传q来的对象必要L接受playNoteq个消息Q于是Guitar和GlassBottle都是可以通过Q因此我卛_以演奏我的Perez 711Q也可以敲玻璃瓶。这U方式叫做dynamic type?/P>

那么static type和dynamic type区别在那呢?static type认ؓQclass是typeQtype是class; subclass是subtypingQsubtyping是subclass(其实q句不严谨,在c++里可以得subclass不是subtypingQ但是java里就没办法了);而dynamic type则认为类型和class没有关系Q类型取决于一个对象能够接受的消息?/P>

那么哪个才是面向对象之真貌呢Q遗憄_static typeq不是最初的面向对象。以对象作ؓ模块化的单位Q始自Simula 67。但是Simula 67q不是一个面向对象系l,以目前的观点来看Q充光是Object-basedQ第一个面向对象语a当推SmalltalkQSmalltalk是dynamic type的。不qSmalltalk不太行Q第一个大面积行的面向对象语a是C++QC++是static type的,正如Lisp是第一个函数式~程语言Q很多Lisp的特性被当作函数式语a的共有特?比如表是最重要的数据结构,轻语?一P所以很多h以ؓ面向对象必然是static typeQ比如老庄和我Q。对于面向对象的误解Q?0%来自C++。也是_80%来自于static type的面向对象系l。将static type面向对象归咎于整个面向对象,我辈实在是大而无当言q其实?/P>

后面我再一一老庄所a之OO不当之处加以说明



Raimundox 2005-12-20 19:58 发表评论
]]>
A Walk on JSR220http://www.aygfsteel.com/raimundox/archive/2005/12/12/23427.htmlRaimundoxRaimundoxMon, 12 Dec 2005 03:08:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/12/23427.htmlhttp://www.aygfsteel.com/raimundox/comments/23427.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/12/23427.html#Feedback1http://www.aygfsteel.com/raimundox/comments/commentRss/23427.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/23427.html从BJUG的maillist里发掘一个我以前的旧帖出来,嘿嘿

以前我和limo同志做过一个Hibernate技巧情色版....嘿嘿Q这ơ发动大家收集一下J2SE 5和JSR 220里的改进design的tips.我下午试?SPAN class=st0 id=st name="st">JSR220的时候,扑ֈ几个

1. Implement Moment-Interval and Moment-Interval-Details Using Iterable<T>

例子Q?比如Order和OrderItemQ典型的一对多Q一般我们这么做

1class Order {
2
3  private List<OrderItem> items;
4
5  public List<OrderItem> getItems() {
6     
7  }

8}


在J2SE5里面Q?/P>

 1class Order implements Iterable<OrderItem> {
 2
 3       private List<OrderItem> items;
 4
 5       public Iterator<OrderItem> iterator() {
 6               return items.iterator;
 7       }

 8
 9      public int getItemCount() {
10             
11      }

12      // and addItem removeItem and others
13}

可以直接来处理Q?/P>

1for (OrderItem item : order) {
2}

从某U程度上利用enhanced for的语法,来简化语法?BR>
trade-off: 不适合多个details 聚合Q适合于简单的moment-interval和moment-interval-details?BR>
2. Annotate Description with @Embeddable, and the Thing it describe with @Entity

例子QProduct和ProductDescription

 1@Embeddable
 2class ProductDescription {
 3  private String name;
 4  private String description;
 5  . and getters and setters
 6}

 7
 8@Entity(access = AccessType.FIELD)
 9class Product {
10  private ProdcutDescription description;
11}

?SPAN class=st0 id=st name="st">JSR220里,如果一个field是embeddableQ而且对该field没有标注为@Transite,以及使用keyword transite,自动按Embedded处理Q这一Ҏ很方?WBR>的?BR>
q个基本没发现trade-off


3. Avoid Database Primary Key in Domain Model Using @EmbeddableSuperclass

例子Q在hibernate里,L要给Domain加一个primary keyQ非常的不爽.
虽然也可以通过l承l构来避免,但是配置文g太多Q?JSR220里,通过自动处理的annotation Q可以节U很大的工作量?BR>

 1@EmbeddableSuperclass
 2class DomainModel {
 3//  modeling your model here
 4}

 5
 6@Entity
 7class PersistentDomainModel extends DomainModel {
 8
 9   private long primaryKey;
10}

q个大家׃目了然了

4. Avoid Database Field in Domain Model Using @AttributeOverride


Annotation虽然化了开发,但是仍然有一个问?WBR>Q就是修改mapping的时候需要修改代码,q个很不?WBR>Q而且影射的时候需要在domain里硬~码field
nameQ这个简直就是恶心,但是q是由办法避免的?/P>

 1@EmbeddableSuperclass
 2class DomainModel {
 3//  modeling your model here
 4}

 5
 6
 7@Entity
 8@AttributeOverride(name="property", column=@Column(name="fieldName"))
 9class PersistentDomainModel extends DomainModel {
10
11   private long primaryKey;
12}

同样Q通过l承来隔L术和DomainQ然后在子类里作部v?WBR>关的动作。然后把DomainModel和PersistentDomainModel 分包Q针对DomainModel~程Q就Ok?WBR>。这个时候Domain会异常的q净.....

5. Model Place as Factory

其实q个是一个通则Q以前好像也讨论q?/P>

1public interface Store {
2  Order newOrder();
3  // and others;
4}

基本上下?个小时的成果p么多Q我是在试?SPAN class=st0 id=st name="st">JSR220 API代替以前我和limo写的那个珍珠商城订单部分得到的一?WBR>tips。M而言Q?SPAN class=st0 id=st name="st">JSR220q是挺好的,我们可以很自然的q用一些模式和OO的手D还避免它的不。同时上q做法在hibernate里也可以做,但是׃比较ȝQ大家一般还是做不到?SPAN class=st0 id=st name="st">JSR220里,正是通过它的毛病我们q么?....Q汗Q,也算体现出约定了?/P>

Raimundox 2005-12-12 11:08 发表评论
]]>
Why Inconsistent Concepts Considered Harmfulhttp://www.aygfsteel.com/raimundox/archive/2005/12/10/23238.htmlRaimundoxRaimundoxFri, 09 Dec 2005 18:17:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/10/23238.htmlhttp://www.aygfsteel.com/raimundox/comments/23238.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/10/23238.html#Feedback2http://www.aygfsteel.com/raimundox/comments/commentRss/23238.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/23238.htmltaol我找了一个非常好的题?

so, you think the consistent thing means a lot? But how do you think the gracious or elegant feeling mean to the real expressiveness of business requirements? We can see lisp is very successful in researching area because of the simplicity nature inside which is also true to Smalltalk. But why they aren't successful in biz world? I think that is the problem you should further study, "how can the consistent feeling mean something to our everyday programming life?".


我承认以前没有考虑到这个问题,因ؓ我以求概念一致性是一U不a自明的天性。那么ؓ什么要一致性很重要呢?我有q样一些想法?/p>

1. 复杂?/p>

概念不一致生首先生的一个恶果就是复杂性,q里我将举两个例子?br>
W一个关于Lisp的。Lisp本nh一个很一致很单的计算模型——?演算。在q个计算模型中,基本元素是函敎ͼλq算W,·q算W。语义也是简单明的Qlambdaq算W提取出函数中的自由变量Q然后再由apply对自由变量赋倹{整个计过E就是函敎ͼW号Q求值的q程。例如对于函数x + yQ我们可以这h求倹{?/p>

((λx (λy . x + y)·34)
=((λx. x+34)
=4 + 3
=7

׃Lisp多少可以认ؓ是?演算的一U实玎ͼ我们可以cM写出Lisp代码

(define f (lambda x (lambda y (+ x y))))
(apply (apply f 
34)

或者更加简单的写ؓ

(define (f x y) (+ x y))
(f 
3 4)

所有在Lisp中的E序Q我们都可以用一U一致的概念来表达,是W号求|我们对一个符号应用一些|然后q个W号完成计算q把l构q回l我们,在计的q程中,W号对外部环境没有Q何破坏和依赖。但是Lisp中引入了赋|于是存在一些符P不仅仅是来计,同时他们q能改变环境?/p>

(define (bad-f x y) 
  (begin 
     (set
! z 5)
     (
+ x y)))

q个函数不仅仅求x + y的|同时修改了符号Z的倹{赋值的引入破坏了函数只求D不影响环境q个概念的一致性。于是我们不得不L一个更加复杂的也更加؜q计算模型Q来代替单优雅的λ 演算。于是不一致的概念带来了思维上的复杂?不过Lisp中的概念不一致除了生了复杂之外Q还Ȁ发了Z对于单计模型的向往从而生了函数式编E风|q也是我最q~程风格之一)?/p>

概念不一致带来的复杂性距L们最q的应该是Java中的单类型,Java本n是一个单根的面向对象语言Q从概念上讲一切都应该是对象,而且׃性能考虑而出现的单类型,引入了代数性的世界观的同时Q破坏了面向对象的一致概cJava中虽然有包装cL做补偿,但是仍然不能弥补概念上的断裂。我们可以用

1new Integer(3)

来代表对象概念中?Q但?/p>

3 + 4 * 5

不能对等的翻译ؓ:

1new Integer(3+ new Integer(4* new Integer(5)

单类型具有的q算W和对象cd的消息发送概念上是不一致的。虽然我们可以在Java 5中用上q的代码Q但是Java 5的Auto-Boxing更多的把对象cd当作单类型进行数据运,而不是像C++中的q算W重载一h数据q算当作一U特D消息传递,虽然语法上有怼的功能,但是概念上大异其,对于我这个OO分子而言QJava 5的Auto-Boxing实在是恶心到不行。同时简单类型和对象cd在赋D义和存储模型上也存在很大的不一_q种不一致性在使用Collection API的时候带来了一些复杂度。(q记得Commons Collection里那些Primitive Collection吧?Q?br>
2.副作?/p>

概念不一致生的W二个恶果就是副作用Q我大概想了一下都有哪些可能的副作用,l果让我很寒Q我能想到的副作用,大多数是׃在另一U模型中引入了冯语言的因素从而造成了概念上的不一致而引L。其中最Zh知的....q是赋值在函数式编E中的副作用...q个在函数式~程C֌有很q泛的讨论,我只说一点,Z么命令语a是有害的?/p>

冯语a或者说命o式语a主要用于ȝ对计机操作的序列,q不兛_序列的内在关pR也是_我们可以把一些完全没有联pȝ指o写在一赗因此冯语言在语义上毫无建树Q同时在抽象上也止步于子E序Q一砣指令和另一砣指令)。冯语言h很强的时间耦合性在存储上也强烈的們֐于线性存储。目前大多数隑֤理的问题Q可以归lؓ计算模型和操作语义的不一_甚至有些学者认为是冯结构严重制U了计算机的发展。因此冯语言被函数社区看作一个很危险的副作用Q极力避免之?/p>

概念的不一致生的副作用在淯的OO语言中也很明显,其是在命o式语a中加入面向对象机Ӟ而且使用面向对象作ؓcdpȝ的扩展,使用q程式的Ҏ来控制流E。过E和对象的不一致本w就l了E序员一U暗C,你可以用对象技术来构造类型系l,然后使用q程的方法来操作他。明昄副作用们很容易用过E化E序Q从而得对象带来的好处被很大的削弱了(当然我们有重构来弥补q个错误Q,比如下面一个例?我们很容易从写出下面的代码:

1if (order.getState() == Order.CANCEL)
2   do something for cancel;
3else if(order.getState() == Order.PAID)
4   do something for paid;
5else if(order.getState() == Order.DELIVERY)
6   do something for delivery

而不?br>

 1public abstract OrderState {
 2
 3   protected Order _order;
 4   
 5   protected OrderState(Order order){
 6      _order = order;
 7   }

 8    
 9   public abstract void handler();
10}

11
12class CancelState extends OrderState {
13
14   public void handler() {
15      do something for cancel;
16   }

17}

18
19order.getState().handle();

因ؓ存在q程性的关键字if, while,处于方便的考虑Q我们会写出W一U风格的代码Q而考虑到易于维护,我们应该写第二种风格的代码。存在两U不一致的书写代码的风|q个时候,副作用取决于使用的语aOO的程度,比如在C++里更Ҏ写出W一U风格的代码Q而在Ruby和Smalltalk中,更容易写出第二种风格的代码?br>

3.递归的构造Y?/p>

q个虽然跟概念一致有养I但是一个更大的主题Q待l吧?/p>

4.优雅Q美感和无名品质

概念的一致性会产生一U优雅的感Q我觉得我们都有q种感觉Q如果我们能用一U一致的Ҏ理解且统一的方式来处理多种不同的复杂的问题Q那么我们就会觉得这U方法很优雅Q也很具有美感。类比物理中的牛定律,开普勒定律Q麦克斯韦方E,都是q种单一致而解军_杂问题的完美CZ。我们更Ҏ感觉C致的感念产生的美感,而不一致的概念往往很难令我ƣ赏。或许无名品质是我对一致的概念的一U模p的审美吧?/p>

我大抵能惛_的就q么多,不知tao是否满意我的{卷?/p>

 



Raimundox 2005-12-10 02:17 发表评论
]]>
Apologize to Object-Oriented Methodologyhttp://www.aygfsteel.com/raimundox/archive/2005/12/08/22986.htmlRaimundoxRaimundoxThu, 08 Dec 2005 07:11:00 GMThttp://www.aygfsteel.com/raimundox/archive/2005/12/08/22986.htmlhttp://www.aygfsteel.com/raimundox/comments/22986.htmlhttp://www.aygfsteel.com/raimundox/archive/2005/12/08/22986.html#Feedback1http://www.aygfsteel.com/raimundox/comments/commentRss/22986.htmlhttp://www.aygfsteel.com/raimundox/services/trackbacks/22986.html最q学习了一下SmalltalkQ然后深q喜欢上了q个古老的语言。Smalltalk语言只具有一个很的语言核心Q这个核心由大约10几个关键字和一些基的面向对象语义构成。而且关键字都是象: . ; ( ) [ ] | := 之类的简单符Pq没有提供最基本控制的流E。最开始的时候这让我很迷惑,虽然循环l构可以用递归表示Q但是分支怎么办?然后发现了一个很LҎ,Smalltalk可以仅仅通过面向对象的语义来实现分支l构Q其实就是State PatternQ,具体的代码如?/P>

Boolean>>ifTrue: aBlock
  self subclassResponsibility

Boolean>>ifFalse: aBlock
  self subclassResponsibility

True>>ifTrue: aBlock
  ^aBlock value.

True>>ifFalse: aBlock
  ^nil.

False>>ifTrue: aBlock
  ^nil.

False>>ifFalse: aBlock
  ^aBlock value.

然后可以,

4 ? ifTrue: [Transcript show: 'Hello']

因ؓ在Smalltalk里,一切皆对象且从左到x|于是4 > 3 q回trueQtrue是类True的唯一实例Q然后就可以对它发送消息,ifTrue:Q于是调用了^aBlock value.来对传进ȝBlockClosure求倹{?/P>


下面是类似的java的类g码?/P>

 

 1public class abstract Boolean {
 2   public static final TRUE = new True();
 3   public static final FALSE = new False();
 4
 5   public abstract Object ifTrue(Block aBlock);
 6   public abstract Object ifFalse(Block aBlock);
 7}

 8
 9class True extends Boolean {
10
11   public Object ifTrue(Block aBlock) {
12       return aBlock.execute();
13   }

14
15   public Object ifFalse(Block aBlock) {
16       return null;
17   }

18}

19
20class False extends Boolean {
21
22   public Object ifTrue(Block aBlock) {
23       return null;
24   }

25
26   public Object ifFalse(Block aBlock) {
27       return aBlock.execute();       
28   }

29}

30

4 ? ifTrue: [Transcript show: 'Hello']可以对应翻译ؓ:

 

1Boolean condition = new Integer(4).isGreaterThan(new Integer(3));
2condition.ifTrue(new BlockClosure() {
3   public Object execite() {
4      System.out.println("Hello");
5      return null;
6   }

7}
);
8
9

q个看似单的应用Q却带来了两个有深刻影响的性质?/P>

W一Q由于if,else{结构不再是预定义的语法了,而与我们自己写的代码一P属于莫一个类的特定消息,那么也就意味着Q我们可以像ifTrue一P定义自己的分支结构?BR>比如
   aUser ifNotRegistered: [ do redirect to register page ]
         ifExpired: [ do redirect to active page ]

在不考虑性能优化的前提下QSmalltalk认ؓ?BR>   4 >3 ifTrue: [do something]
        ifFalse: [do somthing]

是具有一L语义的。ƈ不因为Boolean属于Kernel有什么不同。因此控制结构也属于一个可~程的因素,q就是Smalltalk的轻语法Ҏ?/P>

W二Q在单的语法和完全的面向对象语义中,构造与冯诺依曼式语a完全{h的能力(q种能力在语法上表现|分支QP代和子程序调用)Q于是我们可以完全用一致的面向对象的方法来构造Y件?/P>

很长一D|间以来,我都认ؓ面向对象Ҏ论是在命令式的冯Z曼式语言的基上,通过引入cdpȝ然后修修补补的得到的Q由于冯ZDa式的语言是面向操作层面上的,只是Z更好的刻L作计的一个命令的序列Q因此冯语言不可避免的具有不完备的语义,混ؕ的抽象表达以及等{一pd的问题。作为冯语言的一个大补丁的面向对象方法,我也惛_然的以ؓ他虽然有了些q步Q但是基问题上面q是不能避免的,加之面向对象~Z一U一致的构造方法,很多时候我们不得不回归到命令式或者过E式的方法来构造系l,从而破坏掉一U一致清晰的思\Q在q程和对象之间不住地权衡Q比如Domain Model之争Q,q个让h非常的不爽。在试了一些面向对象语a之后Q我是在95q接触C++的时候开始了解面向对象的Q而后主要使用Java做ؓ开发语aQ,我发现这个问题是很难避免Q于是我断言q是面向对象技术本w的问题Q现在看来不q自己所学有限,没有真正用过U面向对象语a而已Q汗颜得很啊。这里向面向对象Ҏ道个歉,嘿嘿?/P>

Raimundox 2005-12-08 15:11 发表评论
]]>
վ֩ģ壺 ˷| | | ȫ| | | ϽϽ| | ʢ| ʳ| | | ¡| | ɽ| ׳| | ؼ| | | | | ޽| | | | | | ɽ| ƽ| | ͡| | | | | ½| »| | Ϸ| Ԫ|