在这里,我想要说的是一个特别具有“中国特艜y的隐喻Q我UC为武侠隐喅R?/p>
毋庸我多做解释,可能很多E序员看到这个词p以勾起丰富的惌。我们中的很多h喜欢把自己所崇敬
和佩服的、Y件界有媄响力的hUC为大侠,q惌己有朝一日能够达C们的境界。(跑题一下,
q个U谓现在g有了一个比较草根的、或者说比较Web2.0的版本——叫做牛人)上个世纪那个个h
英雄M的年代,曄涌现Z大批q样的h物,现在很多Z然习惯称他们为“大侠”——这?br />中包括求伯君、王志东、鲍x、朱崇君...
除此之外Q我们还喜欢重量的出版物UC为武林秘c?把Y件开发的l织团体比作江湖帮派Q?br />要Ş容Y件开发的理想境界Q也怼搬出“飞花摘叶俱可伤人”或“无剑胜有剑”这L句子。所有这?br />都或多或的表明Q武侠深深媄响了大量的程序员Q他们非常喜Ƣ用武侠中的理念来比喻Y件开发过E中
的现象。或许,也是因ؓE序??的生zdq枯燥,需要文化来加一点味道,而他们自觉不自觉?br />选择了武侠。这是所谓的中国特色吧?/p>
我必老实的承认:我自己就曄深受武侠的媄响,q去也一直没有感到有什么不妥。但是,
在前几天看过|上的某些回帖中一些充满武侠隐d道的文字Q突然觉得有些不是滋呟?br />我开始思考:对于软g开发来_武侠是不是一个好的隐喻?l论Q不是不好,而是非常?br />p。武侠和软g开发根本没有什么共同点Q甚臛_以说是水火不容的?/p>
Z么说武侠和Y件开发没有共同点Q武侠讲的是破坏的艺术。太史公说“侠以武犯禁”?br />武侠的意义,在最好的情况下,也仅仅是杀富济贫、除暴安良,是对旧有U序的破坏?br />问题在于Q破坏是痛快惬意的,但破而不立就是纯_的破坏Q没有Q何积极意义?br />破坏以后新的U序如何建立呢?没有哪一个武侠故事ؓ此做出答案,
也没有一个侠客操心这U事。他们在乎的是“十步杀一人,千里不留形”的高手形象Q?br />至于C以后烂摊子谁来收拾?那本大侠可就不着了?/p>
软g开发是Q而不?br />破坏。即使旧的系l非常糟p,我们也没有理由将其付之一炬——这是Z么现代的敏捷
开发者非常强调重构的原因。构造新的代码固然是极具创造快感的工作Q但是Y件开发过
E中q有成打的“肮脏”工作:需求分析,设计Q文档,调试Q维?.....q些工作J冗
而琐,但却是整个开发过E中必不可少的组成部分。想潇洒一下就拍拍屁股Ch?br />E序员没有什么职业素质可a?/p>
武侠中的高手是什么Ş象?天马行空Q独往独来Q神出鬼没。这L人看h很有性格Q?br />但在C企业中恰恰是最忌讳的。而正正经l提倡Team Work的团队反倒在武侠中常常成?br />讥刺的对象——你不妨看看林或全真这L大型团队在金庸小说中被丑化成了什么地步?/p>
武侠所描绘的是农业C会的典型情c一位高手通常只会把自q技Z授给至亲和少数几?br />信得q的弟子Q弟子亦然。这U结构非常脆弱:一旦出CQ何问题,q门技艺很Ҏ失传了?/p>
武侠中的U籍是这样一U东西:你得到它以后Q最好藏之名山,偷偷修炼。一旦泄漏,只会l你
带来杀w之。和师徒授受的问题相同,q样只会让最好的技艺在历史长河中渐渐灭。现代社会和开?br />源代码运动则昄了相反的情况Q知识可以由M取与学习Q而不分门z贵贱。与别h分n
知识也不会给你带来Q何坏处?/p>
武侠成ؓ隐喻带来的恶果就是,E序员以成ؓ“高手”ؓ荣,以炫耀技巧ؓ乐;无视风险
大量采用一些看上去比较炫的新技术;愤世嫉俗以ؓ天下只有自己怀才未遇;不会与h
沟通,|顾客户需求,把不懂技术的用户当白_不会开诚布公,L自己偷偷留一手;
凡此U种Q不能说都是因ؓ武侠毒。但是在E序员中造成了不好的风气Q武侠的影响
是不可忽视的?/p>
武侠是成qh的童话,但Y件开发不是童话。Y件开发要的是脚踏实地Q而不是快意恩仇?br />q在做侠客梦的程序员Q愿你们早点醒来?/p>
值得说明的是Q如果设|Combo为OwnerDraw Variable风格Q则必须重蝲wmMeasureChildҎ来指定每一的高度。如果用OwnerDraw Fixed风格Q则只需要在构造的时候发送一条CB_SETITEMHEIGHT消息p了?br />
另外一U值得考虑的选择是将Win32的ComboBoxEx控g包装成SWT Widget。不q,q需要{换若q结构ƈ提供接口QWin32的ImageList理机制和SWT的Image包装Ҏ差别比较大,使得q种Ҏ实现hȝ的多?br />
既然此\不通,那么C#是如何实现delegate的呢Q过M曑闻过一些内q,不过q次被逼才真的下决心认真去看这斚w的东ѝ原来M$使用的是代码生成的技术:对于每个delegateQC#都会为它生成一个派生于MulticaseDelegate的对象,其中实现了一个和delegate{相同的方法。同Ӟ对delegate的操作符+=?=也会被编译器处理成对MulticaseDelegateҎ的调用?/p>
知道了这一点,接下来就需要看看Java中有没有cM的代码生成技术了。有意思的是,查找的时候发现有消息_Java 6.0QMutangQ中会提供动态代码生成的功能。这的确很吸引hQ不qJava6q在Beta阶段Q眼下还指望不上。其他比较出名的Ҏ是Apache becl和Objectweb ASM了。这两个库都比较底层Q不q还有一个开源的目——cglib——它在内部用了asmQ不q提供了较多的实用功能。据说Hibernate和Spring都用Cq个东西。研I这个库的时候,我一眼看CMethodDelegatecZ—很明显q就是我要找的东西了?/p>
MethodDelegate的设计思想很类gC#的delegate——将接口调用转发l类的一个成员函数。不q阅L档的时候我发现一个问题。MethodDelegate要求其所实现的接口必d有一个公共方法,但是SWT中的许多事g接口都有不止一个方法;比如QSelectionListener有widgetSelected和idgetDefaultSelected两个Ҏ。因此要在SWT中用MethodDelegateQ还
必须再多实现另外一层{发?/p>
了解手段Q接下来的事情就不难了。ȝhQ需要的步骤大致如下Q?br />1、ؓ每种需要实现的事g声明一个接口。这是MethodDelegate的要求?br />2、用一个类实现SWT的事件接口,q将特定的接口调用{发到W一步所实现
的接口?br />3、用MethodDelegate提供的方法,声明事g处理对象QEvent Handler
TargetQ通常ZH体或主部gQ要实现上述的事件接口。下面就来实C下。ؓ了简单v见,需要实现的接口声明Z件{发类的内部接口,以避免维护太多接口文Ӟ因ؓ该接口只需要声明一个方法,所以不会把外部cL得太q复杂。)例如Q处理部仉择事gQwidgetSelectedQ的cd以如下实玎ͼ
package org.yuhao.swt.events;
import net.sf.cglib.reflect.MethodDelegate;
import org.eclipse.swt.events.*;
public class WidgetSelectedHandler implements SelectionListener
{
public WidgetSelectedHandler( Object target, String
methodName )
{
delegate = (IWidgetSelectedDelegate)
MethodDelegate.create( target,
methodName,
IWidgetSelectedDelegate.class );
}
public void widgetDefaultSelected( SelectionEvent e )
{
}
public void widgetSelected( SelectionEvent e )
{
delegate.invoke( e );
}
public void invoke( SelectionEvent e )
{
}
public interface IWidgetSelectedDelegate
{
void invoke( SelectionEvent e );
}
private IWidgetSelectedDelegate delegate;
}
q个接口虽然只有外部cȝ刎ͼ但是必须声明为public的,否则q行会出错(我想大概是因Z码生成以后还是外部类Q需要公开讉K权限Q。ؓ了简化调用,再声明一个处理事件的辅助cEventHandlerQ专门管理将各种事g转发到相应的Handler的工作:
public class EventHandler
{
public EventHandler( Object target )
{
this.target = target;
}
public void handleSelected( Button btn, String methodName )
{
btn.addSelectionListener( new
WidgetSelectedHandler( target, methodName ) );
}
private Object target;
}
q样Q在H口中就可以单的如下处理事gQ?br />public MainShell extends Shell()
{
public MainShell( Display display )
{
......
handler = new EventHandler( this );
handler.handleSelected( btn, "btn_clicked" );
}
public void btn_clicked( SelectionEvent e )
{
...
}
}
q里q需要注意:1、Q何事件处理方法必d明ؓpublic的。这样似乎有q面向对象的装原则Q不q实际上q不会造成什么大问题?、事件方法的{必须和对应的事gҎ相同。例如,widgetSelectedҎ有一个SelectionEvent参数Q那么处理该事g的btn_clickedҎ也必L且只有这一个参数。如果写错了Q那么运行的时候会抛出异常Q说找不到指定的Ҏ。这q是需要程序员的细心来保证。还幸q的是出错的提示非常明显Q不必担心用了q度复杂的技术而找不到真正的出错点?br />