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

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

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

    treenode

    在路上。

    BlogJava 首頁 新隨筆 聯系 聚合 管理
      5 Posts :: 1 Stories :: 53 Comments :: 0 Trackbacks

    在上回的blog中,我抱怨過用Java用內部類來實現事件回調的機制是多么難看和麻煩。在這段時間里,我一直在考慮是否有什么方法可以不用內部類而實現同樣的效果。因為Java語言本身的限制,所以常規方法是行不通的。有人建議用反射——的確通過反射可以調用任意的方法,但是反射效率不佳,對頻繁發生的事件或許不太合適。動態代理也不能解決方法映射的難題。我似乎走進了死胡同。

    既然此路不通,那么C#是如何實現delegate的呢?過去也曾聽聞過一些內幕,不過這次被逼才真的下決心認真去看這方面的東西。原來M$使用的是代碼生成的技術:對于每個delegate,C#都會為它生成一個派生于MulticaseDelegate的對象,其中實現了一個和delegate簽名相同的方法。同時,對delegate的操作符+=和-=也會被編譯器處理成對MulticaseDelegate方法的調用。

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

    MethodDelegate的設計思想很類似于C#的delegate——將接口調用轉發給類的一個成員函數。不過閱讀文檔的時候我發現一個問題。MethodDelegate要求其所實現的接口必須只有一個公共方法,但是SWT中的許多事件接口都有不止一個方法;比如,SelectionListener就有widgetSelected和idgetDefaultSelected兩個方法。因此要在SWT中使用MethodDelegate,還

    必須再多實現另外一層轉發。

    了解手段,接下來的事情就不難了。總結起來,需要的步驟大致如下:
    1、為每種需要實現的事件聲明一個接口。這是MethodDelegate的要求。
    2、用一個類實現SWT的事件接口,并將特定的接口調用轉發到第一步所實現

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

    Target,通常為主窗體或主部件)要實現上述的事件接口。下面就來實現一下。為了簡單起見,將需要實現的接口聲明為事件轉發類的內部接口,以避免維護太多接口文件(因為該接口只需要聲明一個方法,所以不會把外部類搞得太過復雜。)例如,處理部件選擇事件(widgetSelected)的類可以如下實現:

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

    這個接口雖然只有外部類用到,但是必須聲明為public的,否則運行會出錯(我想大概是因為代碼生成以后還是外部類,需要公開訪問權限)。為了簡化調用,再聲明一個處理事件的輔助類EventHandler,專門管理將各種事件轉發到相應的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;
    }

    這樣,在窗口中就可以簡單的如下處理事件:
    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的。這樣似乎有違面向對象的封裝原則,不過實際上并不會造成什么大問題。2、事件方法的簽名必須和對應的事件方法相同。例如,widgetSelected方法有一個SelectionEvent參數,那么處理該事件的btn_clicked方法也必須有且只有這一個參數。如果寫錯了,那么運行的時候會拋出異常,說找不到指定的方法。這還是需要程序員的細心來保證。還算幸運的是出錯的提示非常明顯,不必擔心使用了過度復雜的技術而找不到真正的出錯點。

    posted on 2006-06-27 11:29 TreeNode 閱讀(1216) 評論(0)  編輯  收藏 所屬分類: SWT,JFace和RCPJava技術
    主站蜘蛛池模板: 污视频网站在线免费看| 亚洲精品日韩一区二区小说| 国产精品一区二区三区免费| 亚洲欧好州第一的日产suv| 狼色精品人妻在线视频免费| 女人被免费视频网站| 亚洲色大网站WWW永久网站| 久久精品无码一区二区三区免费| 亚洲va精品中文字幕| 亚洲中文无码永久免费| 亚洲av无码成h人动漫无遮挡| 成在人线av无码免费高潮喷水 | 国产免费拔擦拔擦8X高清在线人 | 久久综合日韩亚洲精品色| 午夜免费啪视频在线观看 | 91黑丝国产线观看免费| 激情综合亚洲色婷婷五月APP| 最近最好的中文字幕2019免费 | 亚洲欧洲国产综合AV无码久久| 永久黄网站色视频免费直播| 亚洲日韩在线中文字幕综合| 国产日产亚洲系列最新| a级毛片免费在线观看| 亚洲最大福利视频网站| 成人免费毛片观看| 一级做a爰黑人又硬又粗免费看51社区国产精品视 | 亚洲国产成人久久精品动漫| 国产又黄又爽又猛免费app| 亚洲aⅴ无码专区在线观看| 国产亚洲精久久久久久无码77777 国产亚洲精品成人AA片新蒲金 | 7777久久亚洲中文字幕蜜桃| 歪歪漫画在线观看官网免费阅读| 久久亚洲中文字幕无码| 亚洲中文字幕无码日韩| 91免费播放人人爽人人快乐| 美女视频黄a视频全免费网站色| 亚洲AV无码乱码在线观看富二代| 欧美在线看片A免费观看| 一级做α爱过程免费视频| 亚洲美女大bbbbbbbbb| 日韩亚洲国产二区|