??xml version="1.0" encoding="utf-8" standalone="yes"?>免费在线国产,在线综合+亚洲+欧美中文字幕,久久超级碰视频 http://www.aygfsteel.com/raimundox/category/5762.html知天之所为,知h之所,至矣。知天之所,天而生也;知h之所,以其知之所知以d知之所不知Q终其天q而不中道夭者:是知之盛也?/description>zh-cn Tue, 20 Apr 2010 10:10:13 GMT Tue, 20 Apr 2010 10:10:13 GMT 60 Misquotation http://www.aygfsteel.com/raimundox/archive/2007/11/28/163761.htmlRaimundox Raimundox Wed, 28 Nov 2007 10:08:00 GMT http://www.aygfsteel.com/raimundox/archive/2007/11/28/163761.html http://www.aygfsteel.com/raimundox/comments/163761.html http://www.aygfsteel.com/raimundox/archive/2007/11/28/163761.html#Feedback 1 http://www.aygfsteel.com/raimundox/comments/commentRss/163761.html http://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. ”
]]> Feng Shui for Standard ML Programmers http://www.aygfsteel.com/raimundox/archive/2007/07/10/129436.htmlRaimundox Raimundox Tue, 10 Jul 2007 13:53:00 GMT http://www.aygfsteel.com/raimundox/archive/2007/07/10/129436.html http://www.aygfsteel.com/raimundox/comments/129436.html http://www.aygfsteel.com/raimundox/archive/2007/07/10/129436.html#Feedback 4 http://www.aygfsteel.com/raimundox/comments/commentRss/129436.html http://www.aygfsteel.com/raimundox/services/trackbacks/129436.html http://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个月口头:"你这写当心坏了项目的风水" ]]> The Keyword 'end' Drives Me Crazy http://www.aygfsteel.com/raimundox/archive/2007/05/11/116864.htmlRaimundox Raimundox Fri, 11 May 2007 12:32:00 GMT http://www.aygfsteel.com/raimundox/archive/2007/05/11/116864.html http://www.aygfsteel.com/raimundox/comments/116864.html http://www.aygfsteel.com/raimundox/archive/2007/05/11/116864.html#Feedback 1 http://www.aygfsteel.com/raimundox/comments/commentRss/116864.html http://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?.. ]]>Church Number http://www.aygfsteel.com/raimundox/archive/2006/10/09/73931.htmlRaimundox Raimundox Sun, 08 Oct 2006 18:32:00 GMT http://www.aygfsteel.com/raimundox/archive/2006/10/09/73931.html http://www.aygfsteel.com/raimundox/comments/73931.html http://www.aygfsteel.com/raimundox/archive/2006/10/09/73931.html#Feedback 2 http://www.aygfsteel.com/raimundox/comments/commentRss/73931.html http://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存储实现点也不是不可能的事?.. ]]>Selenium Better Pratice http://www.aygfsteel.com/raimundox/archive/2006/08/04/61860.htmlRaimundox Raimundox Fri, 04 Aug 2006 13:59:00 GMT http://www.aygfsteel.com/raimundox/archive/2006/08/04/61860.html http://www.aygfsteel.com/raimundox/comments/61860.html http://www.aygfsteel.com/raimundox/archive/2006/08/04/61860.html#Feedback 11 http://www.aygfsteel.com/raimundox/comments/commentRss/61860.html http://www.aygfsteel.com/raimundox/services/trackbacks/61860.html 1. 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 />
]]>ANTLR Lexer Tips http://www.aygfsteel.com/raimundox/archive/2006/03/27/37605.htmlRaimundox Raimundox Mon, 27 Mar 2006 06:44:00 GMT http://www.aygfsteel.com/raimundox/archive/2006/03/27/37605.html http://www.aygfsteel.com/raimundox/comments/37605.html http://www.aygfsteel.com/raimundox/archive/2006/03/27/37605.html#Feedback 4 http://www.aygfsteel.com/raimundox/comments/commentRss/37605.html http://www.aygfsteel.com/raimundox/services/trackbacks/37605.html 阅读全文 ]]> A Patch for Ruby Watir Test Framework http://www.aygfsteel.com/raimundox/archive/2006/01/11/27549.htmlRaimundox Raimundox Wed, 11 Jan 2006 03:30:00 GMT http://www.aygfsteel.com/raimundox/archive/2006/01/11/27549.html http://www.aygfsteel.com/raimundox/comments/27549.html http://www.aygfsteel.com/raimundox/archive/2006/01/11/27549.html#Feedback 2 http://www.aygfsteel.com/raimundox/comments/commentRss/27549.html http://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 功能试 '
成功。最后一步是贡献CQ直接登到rubyforgeQ找到Watir然后submit了两个patchQ一个直接修改watir库的一个是独立的watir-cn的。推荐大家用第二个的patch。地址在:http://rubyforge.org/tracker/index.php?func=detail&aid=3232&group_id=104&atid=489 ]]>A Day of Two Pragmatic Programmers' Life http://www.aygfsteel.com/raimundox/archive/2006/01/10/27469.htmlRaimundox Raimundox Tue, 10 Jan 2006 13:30:00 GMT http://www.aygfsteel.com/raimundox/archive/2006/01/10/27469.html http://www.aygfsteel.com/raimundox/comments/27469.html http://www.aygfsteel.com/raimundox/archive/2006/01/10/27469.html#Feedback 9 http://www.aygfsteel.com/raimundox/comments/commentRss/27469.html http://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... ]]> 丧钟?(4) http://www.aygfsteel.com/raimundox/archive/2005/12/21/24957.htmlRaimundox Raimundox Wed, 21 Dec 2005 07:51:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/21/24957.html http://www.aygfsteel.com/raimundox/comments/24957.html http://www.aygfsteel.com/raimundox/archive/2005/12/21/24957.html#Feedback 2 http://www.aygfsteel.com/raimundox/comments/commentRss/24957.html http://www.aygfsteel.com/raimundox/services/trackbacks/24957.html W?. 一切皆对象和面向对象的理论基础
老庄是反对一切皆对象的,而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 value4 valuen) (lambda (dispatch) (dispatch value1 value2 value3 value4 valuen))) (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>
]]> 丧钟鸣?(3) http://www.aygfsteel.com/raimundox/archive/2005/12/21/24891.htmlRaimundox Raimundox Tue, 20 Dec 2005 16:44:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/21/24891.html http://www.aygfsteel.com/raimundox/comments/24891.html http://www.aygfsteel.com/raimundox/archive/2005/12/21/24891.html#Feedback 1 http://www.aygfsteel.com/raimundox/comments/commentRss/24891.html http://www.aygfsteel.com/raimundox/services/trackbacks/24891.html W? 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是能够演奏单音的。我们可以写出来
1 interface SoloInstrument { 2 SoloInstrument playNote(Note note); 3 }
对于W二个方法,playChord的时候我们要求的cd是能够演奏和弦的Q我们可以写出来
1 interface ChordInstrument { 2 ChordInstrument playChord(Chord note); 3 }
而对于第三个ҎQplayBWV996的时候我们要求既能演奏和弦也能演奏单韻Iq个时候出C个问题,我们怎么处理Instrument的承关p?一个能演奏和u的乐器是否可以演奏单?{案是一般而言是的Q但是也不排除有一些不是这L)?q是我们单的?
1 interface SoloAndChordInstrument extends SoloInstrument, ChordInstrument { 2 }
或?/P>
1 interface 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>
]]>
丧钟鸣?(2) http://www.aygfsteel.com/raimundox/archive/2005/12/21/24889.htmlRaimundox Raimundox Tue, 20 Dec 2005 16:22:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/21/24889.html http://www.aygfsteel.com/raimundox/comments/24889.html http://www.aygfsteel.com/raimundox/archive/2005/12/21/24889.html#Feedback 2 http://www.aygfsteel.com/raimundox/comments/commentRss/24889.html http://www.aygfsteel.com/raimundox/services/trackbacks/24889.html W? 关于"接口"
关于接口的问题老庄说对了,q个东西q不属于面向对象的概念,而且在动态类型面向对象语a(比如Ruby, Smalltalk?Q根本没有这个东ѝ这是一个纯_的静态类型面向对象语a的特性,或者直接说Q接口就是一个纯cd(Type)。还是上ơ的例子Q?/P>
1 interface Instrument { 2 void playNote(Note note); 3 void playChord(Chord chord); 4 } 5 6 in Person Class 7 8 void 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出?
1 interface Instrument { 2 Instrument playNote(Note note); 3 }
同样对于W二个方法我们也可以写出?
1 interface 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>
1 interface 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来实现的
1 class SubClassA: private ImplementationParent { 2 }
q也是C++里ؓC多的subclass不是subtype的例子?/P>
2.cdl承Q这个在C++和java里有Q而在smalltalk,ruby有却不明显?/P>
cdl承的极致就是C++里的U虚父类
1 abstract class Parent { 2 3 public asbtract void method1() = 0 ; 4 public asbtract void method2() = 0 ; 5 }
也就是java里的interface
1 interface Parent { 2 void method1(); 3 void method2(); 4 }
因此Q也明了了Q所谓“面向接口编E”是以类型作为约定的~程。我觉得q点大家一定不陌生Q面向接口的~程里interface都很而且U定明确。但是要说明一点的是,q个东西?面向抽象而不要面向具体编E?其实q不一P所以这个东西也׃仅能是静态类型面向对象的一个惯用法Q还C了原则这么高?/P>
]]> 丧钟鸣?(1) http://www.aygfsteel.com/raimundox/archive/2005/12/20/24851.htmlRaimundox Raimundox Tue, 20 Dec 2005 11:58:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/20/24851.html http://www.aygfsteel.com/raimundox/comments/24851.html http://www.aygfsteel.com/raimundox/archive/2005/12/20/24851.html#Feedback 10 http://www.aygfsteel.com/raimundox/comments/commentRss/24851.html http://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不当之处加以说明
]]> A Walk on JSR220 http://www.aygfsteel.com/raimundox/archive/2005/12/12/23427.htmlRaimundox Raimundox Mon, 12 Dec 2005 03:08:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/12/23427.html http://www.aygfsteel.com/raimundox/comments/23427.html http://www.aygfsteel.com/raimundox/archive/2005/12/12/23427.html#Feedback 1 http://www.aygfsteel.com/raimundox/comments/commentRss/23427.html http://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一般我们这么做
1 class Order { 2 3 private List < OrderItem > items; 4 5 public List < OrderItem > getItems() { 6 7 }8 }
在J2SE5里面Q?/P>
1 class 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>
1 for (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 2 class ProductDescription { 3 private String name; 4 private String description; 5 . and getters and setters 6 } 7 8 @Entity(access = AccessType.FIELD) 9 class 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 2 class DomainModel { 3 // modeling your model here 4 } 5 6 @Entity 7 class 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 2 class DomainModel { 3 // modeling your model here 4 } 5 6 7 @Entity 8 @AttributeOverride(name= " property " , column = @Column(name = " fieldName " )) 9 class 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>
1 public 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> ]]>
Why Inconsistent Concepts Considered Harmful http://www.aygfsteel.com/raimundox/archive/2005/12/10/23238.htmlRaimundox Raimundox Fri, 09 Dec 2005 18:17:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/10/23238.html http://www.aygfsteel.com/raimundox/comments/23238.html http://www.aygfsteel.com/raimundox/archive/2005/12/10/23238.html#Feedback 2 http://www.aygfsteel.com/raimundox/comments/commentRss/23238.html http://www.aygfsteel.com/raimundox/services/trackbacks/23238.html taol我找了一个非常好的题?
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)· 3 )· 4 ) = ((λx. x + 3 )· 4 ) = 4 + 3 = 7
׃Lisp多少可以认ؓ是?演算的一U实玎ͼ我们可以cM写出Lisp代码
(define f (lambda x (lambda y ( + x y)))) (apply (apply f 3 ) 4 )
或者更加简单的写ؓ
(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做补偿,但是仍然不能弥补概念上的断裂。我们可以用
1 new Integer( 3 )
来代表对象概念中?Q但?/p>
3 + 4 * 5
不能对等的翻译ؓ:
1 new 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,比如下面一个例?我们很容易从写出下面的代码:
1 if (order.getState() == Order.CANCEL) 2 do something for cancel; 3 else if (order.getState() == Order.PAID) 4 do something for paid; 5 else if (order.getState() == Order.DELIVERY) 6 do something for delivery
而不?br>
1 public 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 12 class CancelState extends OrderState { 13 14 public void handler() { 15 do something for cancel; 16 }17 }18 19 order.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>
]]> Apologize to Object-Oriented Methodology http://www.aygfsteel.com/raimundox/archive/2005/12/08/22986.htmlRaimundox Raimundox Thu, 08 Dec 2005 07:11:00 GMT http://www.aygfsteel.com/raimundox/archive/2005/12/08/22986.html http://www.aygfsteel.com/raimundox/comments/22986.html http://www.aygfsteel.com/raimundox/archive/2005/12/08/22986.html#Feedback 1 http://www.aygfsteel.com/raimundox/comments/commentRss/22986.html http://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>
1 public 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 9 class 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 20 class 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']可以对应翻译ؓ:
1 Boolean condition = new Integer( 4 ).isGreaterThan( new Integer( 3 )); 2 condition.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>
]]>
վ֩ģ壺
˷ |
|
潭 |
ȫ |
|
|
ϽϽ |
|
ʢ |
ʳ |
|
|
¡ |
|
ɽ |
׳ |
|
ؼ |
|
|
|
|
|
|
|
|
|
|
ɽ |
ƽ |
|
͡ |
|
|
|
|
½ |
» |
|
Ϸ |
Ԫ |