既然此\不通,那么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 />