??xml version="1.0" encoding="utf-8" standalone="yes"?>www.亚洲在线,精品亚洲综合,国产区视频在线http://www.aygfsteel.com/treenode/archive/2006/06/27/55289.htmlTreeNodeTreeNodeTue, 27 Jun 2006 03:29:00 GMThttp://www.aygfsteel.com/treenode/archive/2006/06/27/55289.htmlhttp://www.aygfsteel.com/treenode/comments/55289.htmlhttp://www.aygfsteel.com/treenode/archive/2006/06/27/55289.html#Feedback0http://www.aygfsteel.com/treenode/comments/commentRss/55289.htmlhttp://www.aygfsteel.com/treenode/services/trackbacks/55289.html在上回的blog中,我抱怨过用Java用内部类来实C件回调的机制是多么难看和ȝ。在q段旉里,我一直在考虑是否有什么方法可以不用内部类而实现同L效果。因为Java语言本n的限Ӟ所以常规方法是行不通的。有人徏议用反射——的通过反射可以调用L的方法,但是反射效率不佳Q对频繁发生的事件或怸太合适。动态代理也不能解决Ҏ映射的难题。我g走进了死胡同?/p>

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



TreeNode 2006-06-27 11:29 发表评论
]]>
内部c让我厌恶Javahttp://www.aygfsteel.com/treenode/archive/2006/06/15/53098.htmlTreeNodeTreeNodeThu, 15 Jun 2006 14:37:00 GMThttp://www.aygfsteel.com/treenode/archive/2006/06/15/53098.htmlhttp://www.aygfsteel.com/treenode/comments/53098.htmlhttp://www.aygfsteel.com/treenode/archive/2006/06/15/53098.html#Feedback26http://www.aygfsteel.com/treenode/comments/commentRss/53098.htmlhttp://www.aygfsteel.com/treenode/services/trackbacks/53098.html
        b.addSelectionListener( new SelectionAdapter()
        {
            
public void widgetSelected( SelectionEvent e )
            {
                Runnable longJob 
= new Runnable()
                {
                    
boolean    done    = false;
                    
int        id;

                    
public void run()
                    {
                        Thread thread 
= new Thread( new Runnable()
                        {
                            
public void run()
                            {
                                id 
= nextId[0]++;
                                display.syncExec( 
new Runnable()
                                {
                                    
public void run()
                                    {
                                        
if ( text.isDisposed() )
                                            
return;
                                        text
                                                .append( 
"\nStart long running task "
                                                        
+ id );
                                    }
                                } );
                                
for ( int i = 0; i < 100000; i++ )
                                {
                                    
if ( display.isDisposed() )
                                        
return;
                                    System.out
                                            .println( 
"do task that takes a long time in a separate thread "
                                                    
+ id );
                                }
                                
if ( display.isDisposed() )
                                    
return;
                                display.syncExec( 
new Runnable()
                                {
                                    
public void run()
                                    {
                                        
if ( text.isDisposed() )
                                            
return;
                                        text
                                                .append( 
"\nCompleted long running task "
                                                        
+ id );
                                    }
                                } );
                                done 
= true;
                                display.wake();
                            }
                        } );
                        thread.start();
                        
while ( !done && !shell.isDisposed() )
                        {
                            
if ( !display.readAndDispatch() )
                                display.sleep();
                        }
                    }
                };
                BusyIndicator.showWhile( display, longJob );
            }
        } );
另外一U:
        delegate void NotifyStartDelegate( int threadId );
        
delegate void NotifyFinishDelegate( int threadId );
        
        btnInvoke.Click 
+= BtnInvokeClick;
        
        
void BtnInvokeClick(object sender, System.EventArgs e)
        {
            text.Text 
= "invoke long running job";
            
            Cursor 
= Cursors.WaitCursor;
            Thread thread 
= new Thread( new ThreadStart(ThreadProc) );
            thread.Start();
        }
        
        
private void ThreadProc()
        {
            
int threadId = nextId ++;
            
bool done = false;
            
            
if ( IsDisposed )
                
return;
            
            Invoke( 
new NotifyStartDelegate(notifyThreadStart), new object[] { threadId } );
            
for ( int i=0; i<100000; i++ )
            {
                
if ( IsDisposed )
                    
return;
                Console.WriteLine( 
"do task that takes a long time in a separate thread " + threadId );
            }
        
            
if ( IsDisposed )
                
return;
            Invoke( 
new NotifyFinishDelegate(notifyThreadFinish), new object[] { threadId } );
            done 
= true;
        }
        
        
private void notifyThreadStart( int threadId )
        {
            text.Text 
+= "\r\nStart long task " + threadId;
            threadCount 
++;
        }
        
        
private void notifyThreadFinish( int threadId )
        {
            text.Text 
+= "\r\nCompleted long running task " + threadId;    
            threadCount 
--;
            
if ( threadCount == 0 )
                Cursor 
= Cursors.Default;
        }
        
        
private int nextId = 0;
        
private int threadCount = 0;

我在另一个地方也抱怨过Q在所有我了解的语aҎ里面,没有一U像Java内部cM栯我觉得反感——甚臛_了恶心的地步。大多作B/Spȝ的JavaE? 序员可能不会有这L感觉Q因为那个领域基本上很少会用到这个概c可是在C/SQ不用Swingq是SWTQ内部类都是l不q去的一座大山。在阅读Eclipse站点上许多代码示例以后,我终于有了痛苦到——一点也不夸张——想要作呕的地步。上面第一D代码就是让我感到窝心的代码之一Q仅仅是其中之一Q还不是最丑陋的)。我惻IJava 语言的发明者大概从来就没写q桌面程序;他根本也不打ؓq个领域的程序员提供一U比较好的事件回调机制?br />
内部cL什么问题呢Q首先,你愿意在ȝ代码逻辑之前Q先׃好几分钟L清楚“这个括号到底是和哪个配对”这U蠢问题吗?你不妨回头看看第一D늚代码Q想惌D其实相当简单的E序Q是不是真的值得用这么多括号去考验你的智力?br />
内部cL对封装的严重破坏。它对外部类的Q何私有变量都有完全的讉K权限——如果你H然发现某个变量的内容不对劲了,你不能仅仅在setXXX里面加个? 点就指望能捕获到错误Q真正的元凶可能是内部类里面的哪一句呢。如果内部类都非常简单,那倒也没什么。可是当内部cȝ来实C件的时候,你就没法指望它一 直那么简单了?br />
内部cL试的盲区。TDDL_要测试,试Q所有包含逻辑的类都应当通过充分的测试。可是内部类怎么试Q只要想惛_能知道,大多数内部类是根本没法测试的Q它和外部类实在是耦合的太紧密了。匿名内部类的问题更严重——它是绝Ҏ法测试的。你怎么试一个连名字都没有的ҎQ?br />
不管有意无意Q内部类在(臛_我看到的Q实践中事实上鼓׃不好的编E风根{就是说Q它q背了DRYQDon't Repeat YourselfQ的原则。比如,button.addSelectionListener后面几乎L跟着SelectionAdapter+括号+ widgetSelected原型?一堆括PDisplay.asyncExec后面L要写上new Runnble()Qvoid runQ)Q括P{等。千一律的东西Q可是又不得不写。而且Q几乎没有什么好的办法可以改q!因ؓ语法的规则要求你必须q样做。每天写q些无聊的东 西,你的话会不会烦?哦,工具是有的。可是工具只负责生成代码Q以后的l护q是要你来做——不是么Q?br />

TreeNode 2006-06-15 22:37 发表评论
]]>
SWT: 深入内幕之消息机制探U(上篇Q?/title><link>http://www.aygfsteel.com/treenode/archive/2006/06/03/50114.html</link><dc:creator>TreeNode</dc:creator><author>TreeNode</author><pubDate>Sat, 03 Jun 2006 04:46:00 GMT</pubDate><guid>http://www.aygfsteel.com/treenode/archive/2006/06/03/50114.html</guid><wfw:comment>http://www.aygfsteel.com/treenode/comments/50114.html</wfw:comment><comments>http://www.aygfsteel.com/treenode/archive/2006/06/03/50114.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.aygfsteel.com/treenode/comments/commentRss/50114.html</wfw:commentRss><trackback:ping>http://www.aygfsteel.com/treenode/services/trackbacks/50114.html</trackback:ping><description><![CDATA[     摘要: 本文试图透过SWT面向对象的封装,深入研究界面框架的构造中最复杂也可以说是最有趣的问题之一——即界面框架如何以面向对象的方式实现操作pȝ底层的消息机制?nbsp; <a href='http://www.aygfsteel.com/treenode/archive/2006/06/03/50114.html'>阅读全文</a><img src ="http://www.aygfsteel.com/treenode/aggbug/50114.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.aygfsteel.com/treenode/" target="_blank">TreeNode</a> 2006-06-03 12:46 <a href="http://www.aygfsteel.com/treenode/archive/2006/06/03/50114.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss> <footer> <div class="friendship-link"> <a href="http://www.aygfsteel.com/" title="狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频">狠狠久久亚洲欧美专区_中文字幕亚洲综合久久202_国产精品亚洲第五区在线_日本免费网站视频</a> </div> </footer> վ֩ģ壺 <a href="http://" target="_blank">֦</a>| <a href="http://" target="_blank">Ѯ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʡ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ӫ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ޭ</a>| <a href="http://" target="_blank">ݳ</a>| <a href="http://" target="_blank">̶</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ˮ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ű</a>| <a href="http://" target="_blank">п</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">˺</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ʦ</a>| <a href="http://" target="_blank">ԭ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">Ϸ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">ɽ</a>| <a href="http://" target="_blank">¡</a>| <a href="http://" target="_blank">Ȫ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank">̨</a>| <a href="http://" target="_blank">Ĭ</a>| <a href="http://" target="_blank">˳</a>| <a href="http://" target="_blank">Դ</a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <a href="http://" target="_blank"></a>| <script> (function(){ var bp = document.createElement('script'); var curProtocol = window.location.protocol.split(':')[0]; if (curProtocol === 'https') { bp.src = 'https://zz.bdstatic.com/linksubmit/push.js'; } else { bp.src = 'http://push.zhanzhang.baidu.com/push.js'; } var s = document.getElementsByTagName("script")[0]; s.parentNode.insertBefore(bp, s); })(); </script> </body>