<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    treenode

    在路上。

    BlogJava 首頁(yè) 新隨筆 聯(lián)系 聚合 管理
      5 Posts :: 1 Stories :: 53 Comments :: 0 Trackbacks

    在上回的blog中,我抱怨過(guò)用Java用內(nèi)部類來(lái)實(shí)現(xiàn)事件回調(diào)的機(jī)制是多么難看和麻煩。在這段時(shí)間里,我一直在考慮是否有什么方法可以不用內(nèi)部類而實(shí)現(xiàn)同樣的效果。因?yàn)镴ava語(yǔ)言本身的限制,所以常規(guī)方法是行不通的。有人建議用反射——的確通過(guò)反射可以調(diào)用任意的方法,但是反射效率不佳,對(duì)頻繁發(fā)生的事件或許不太合適。動(dòng)態(tài)代理也不能解決方法映射的難題。我似乎走進(jìn)了死胡同。

    既然此路不通,那么C#是如何實(shí)現(xiàn)delegate的呢?過(guò)去也曾聽(tīng)聞過(guò)一些內(nèi)幕,不過(guò)這次被逼才真的下決心認(rèn)真去看這方面的東西。原來(lái)M$使用的是代碼生成的技術(shù):對(duì)于每個(gè)delegate,C#都會(huì)為它生成一個(gè)派生于MulticaseDelegate的對(duì)象,其中實(shí)現(xiàn)了一個(gè)和delegate簽名相同的方法。同時(shí),對(duì)delegate的操作符+=和-=也會(huì)被編譯器處理成對(duì)MulticaseDelegate方法的調(diào)用。

    知道了這一點(diǎn),接下來(lái)就需要看看Java中有沒(méi)有類似的代碼生成技術(shù)了。有意思的是,查找的時(shí)候發(fā)現(xiàn)有消息說(shuō),Java 6.0(Mutang)中將會(huì)提供動(dòng)態(tài)代碼生成的功能。這的確很吸引人,不過(guò)Java6還在Beta階段,眼下還指望不上。其他比較出名的方法就是Apache becl和Objectweb ASM了。這兩個(gè)庫(kù)都比較底層,不過(guò)還有一個(gè)開源的項(xiàng)目——cglib——它在內(nèi)部使用了asm,不過(guò)提供了較多的實(shí)用功能。據(jù)說(shuō)Hibernate和Spring都用到了這個(gè)東西。研究這個(gè)庫(kù)的時(shí)候,我一眼看到了MethodDelegate類——很明顯這就是我要找的東西了。

    MethodDelegate的設(shè)計(jì)思想很類似于C#的delegate——將接口調(diào)用轉(zhuǎn)發(fā)給類的一個(gè)成員函數(shù)。不過(guò)閱讀文檔的時(shí)候我發(fā)現(xiàn)一個(gè)問(wèn)題。MethodDelegate要求其所實(shí)現(xiàn)的接口必須只有一個(gè)公共方法,但是SWT中的許多事件接口都有不止一個(gè)方法;比如,SelectionListener就有widgetSelected和idgetDefaultSelected兩個(gè)方法。因此要在SWT中使用MethodDelegate,還

    必須再多實(shí)現(xiàn)另外一層轉(zhuǎn)發(fā)。

    了解手段,接下來(lái)的事情就不難了。總結(jié)起來(lái),需要的步驟大致如下:
    1、為每種需要實(shí)現(xiàn)的事件聲明一個(gè)接口。這是MethodDelegate的要求。
    2、用一個(gè)類實(shí)現(xiàn)SWT的事件接口,并將特定的接口調(diào)用轉(zhuǎn)發(fā)到第一步所實(shí)現(xiàn)

    的接口。
    3、用MethodDelegate提供的方法,聲明事件處理對(duì)象(Event Handler

    Target,通常為主窗體或主部件)要實(shí)現(xiàn)上述的事件接口。下面就來(lái)實(shí)現(xiàn)一下。為了簡(jiǎn)單起見(jiàn),將需要實(shí)現(xiàn)的接口聲明為事件轉(zhuǎn)發(fā)類的內(nèi)部接口,以避免維護(hù)太多接口文件(因?yàn)樵摻涌谥恍枰暶饕粋€(gè)方法,所以不會(huì)把外部類搞得太過(guò)復(fù)雜。)例如,處理部件選擇事件(widgetSelected)的類可以如下實(shí)現(xiàn):

    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;
    }

    這個(gè)接口雖然只有外部類用到,但是必須聲明為public的,否則運(yùn)行會(huì)出錯(cuò)(我想大概是因?yàn)榇a生成以后還是外部類,需要公開訪問(wèn)權(quán)限)。為了簡(jiǎn)化調(diào)用,再聲明一個(gè)處理事件的輔助類EventHandler,專門管理將各種事件轉(zhuǎn)發(fā)到相應(yīng)的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;
    }

    這樣,在窗口中就可以簡(jiǎn)單的如下處理事件:
    public MainShell extends Shell()
    {
    ??public MainShell( Display display )
    ?{
    ??......
    ??handler = new EventHandler( this );
    ??handler.handleSelected( btn, "btn_clicked" );
    ?}

    ?public void btn_clicked( SelectionEvent e )
    ?{
    ??...
    ?}
    }

    這里還需要注意:1、任何事件處理方法必須聲明為public的。這樣似乎有違面向?qū)ο蟮姆庋b原則,不過(guò)實(shí)際上并不會(huì)造成什么大問(wèn)題。2、事件方法的簽名必須和對(duì)應(yīng)的事件方法相同。例如,widgetSelected方法有一個(gè)SelectionEvent參數(shù),那么處理該事件的btn_clicked方法也必須有且只有這一個(gè)參數(shù)。如果寫錯(cuò)了,那么運(yùn)行的時(shí)候會(huì)拋出異常,說(shuō)找不到指定的方法。這還是需要程序員的細(xì)心來(lái)保證。還算幸運(yùn)的是出錯(cuò)的提示非常明顯,不必?fù)?dān)心使用了過(guò)度復(fù)雜的技術(shù)而找不到真正的出錯(cuò)點(diǎn)。

    posted on 2006-06-27 11:29 TreeNode 閱讀(1218) 評(píng)論(0)  編輯  收藏 所屬分類: SWT,JFace和RCPJava技術(shù)

    只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。


    網(wǎng)站導(dǎo)航:
     
    主站蜘蛛池模板: 青青草a免费线观a| 中文字幕无码视频手机免费看| 国产麻豆剧传媒精品国产免费| 亚洲制服丝袜中文字幕| 在线免费观看亚洲| 337p日本欧洲亚洲大胆精品555588| 免费国产污网站在线观看| 久久精品国产精品亚洲色婷婷| 51视频精品全部免费最新| 亚洲人成网站在线观看播放青青| 最新欧洲大片免费在线 | 美女视频黄a视频全免费网站色| 国产小视频在线免费| 特级做a爰片毛片免费看| 久久亚洲高清综合| 久久免费动漫品精老司机| 久久久久亚洲AV片无码下载蜜桃 | 老色鬼久久亚洲AV综合| 黄色成人免费网站| 亚洲色偷精品一区二区三区| 免费国产精品视频| 最好免费观看高清在线| 亚洲人成综合在线播放| 国产极品美女高潮抽搐免费网站| 一级毛片a免费播放王色电影| 亚洲第一精品福利| 免费高清av一区二区三区| 一区二区三区视频免费| 亚洲AV日韩AV永久无码下载| 午夜小视频免费观看| 国产黄在线观看免费观看不卡| 亚洲四虎永久在线播放| 成人免费午夜视频| 久久久WWW免费人成精品| 亚洲日韩乱码中文无码蜜桃臀| 四虎国产精品免费久久影院| 嫩草在线视频www免费观看| 亚洲一区AV无码少妇电影| 国产亚洲A∨片在线观看 | 波多野结衣视频在线免费观看| 日韩视频在线观看免费|