﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>BlogJava-treenode-随笔分类-Java技术</title><link>http://www.blogjava.net/treenode/category/11826.html</link><description>在路上。</description><language>zh-cn</language><lastBuildDate>Tue, 27 Feb 2007 21:43:47 GMT</lastBuildDate><pubDate>Tue, 27 Feb 2007 21:43:47 GMT</pubDate><ttl>60</ttl><item><title>用cglib代码生成避开烦人的内部类</title><link>http://www.blogjava.net/treenode/archive/2006/06/27/55289.html</link><dc:creator>TreeNode</dc:creator><author>TreeNode</author><pubDate>Tue, 27 Jun 2006 03:29:00 GMT</pubDate><guid>http://www.blogjava.net/treenode/archive/2006/06/27/55289.html</guid><wfw:comment>http://www.blogjava.net/treenode/comments/55289.html</wfw:comment><comments>http://www.blogjava.net/treenode/archive/2006/06/27/55289.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.blogjava.net/treenode/comments/commentRss/55289.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/treenode/services/trackbacks/55289.html</trackback:ping><description><![CDATA[
		<p>在上回的blog中，我抱怨过用Java用内部类来实现事件回调的机制是多么难看和麻烦。在这段时间里，我一直在考虑是否有什么方法可以不用内部类而实现同样的效果。因为Java语言本身的限制，所以常规方法是行不通的。有人建议用反射——的确通过反射可以调用任意的方法，但是反射效率不佳，对频繁发生的事件或许不太合适。动态代理也不能解决方法映射的难题。我似乎走进了死胡同。</p>
		<p>既然此路不通，那么C#是如何实现delegate的呢？过去也曾听闻过一些内幕，不过这次被逼才真的下决心认真去看这方面的东西。原来M$使用的是代码生成的技术：对于每个delegate，C#都会为它生成一个派生于MulticaseDelegate的对象，其中实现了一个和delegate签名相同的方法。同时，对delegate的操作符+=和-=也会被编译器处理成对MulticaseDelegate方法的调用。</p>
		<p>知道了这一点，接下来就需要看看Java中有没有类似的代码生成技术了。有意思的是，查找的时候发现有消息说，Java 6.0（Mutang）中将会提供动态代码生成的功能。这的确很吸引人，不过Java6还在Beta阶段，眼下还指望不上。其他比较出名的方法就是Apache becl和Objectweb ASM了。这两个库都比较底层，不过还有一个开源的项目——cglib——它在内部使用了asm，不过提供了较多的实用功能。据说Hibernate和Spring都用到了这个东西。研究这个库的时候，我一眼看到了MethodDelegate类——很明显这就是我要找的东西了。</p>
		<p>MethodDelegate的设计思想很类似于C#的delegate——将接口调用转发给类的一个成员函数。不过阅读文档的时候我发现一个问题。MethodDelegate要求其所实现的接口必须只有一个公共方法，但是SWT中的许多事件接口都有不止一个方法；比如，SelectionListener就有widgetSelected和idgetDefaultSelected两个方法。因此要在SWT中使用MethodDelegate，还</p>
		<p>必须再多实现另外一层转发。</p>
		<p>了解手段，接下来的事情就不难了。总结起来，需要的步骤大致如下：<br />1、为每种需要实现的事件声明一个接口。这是MethodDelegate的要求。<br />2、用一个类实现SWT的事件接口，并将特定的接口调用转发到第一步所实现</p>
		<p>的接口。<br />3、用MethodDelegate提供的方法，声明事件处理对象（Event Handler </p>
		<p>Target，通常为主窗体或主部件）要实现上述的事件接口。下面就来实现一下。为了简单起见，将需要实现的接口声明为事件转发类的内部接口，以避免维护太多接口文件（因为该接口只需要声明一个方法，所以不会把外部类搞得太过复杂。）例如，处理部件选择事件（widgetSelected）的类可以如下实现：</p>
		<p>package org.yuhao.swt.events;</p>
		<p>import net.sf.cglib.reflect.MethodDelegate;</p>
		<p>import org.eclipse.swt.events.*;</p>
		<p>public class WidgetSelectedHandler implements SelectionListener<br />{<br /> public WidgetSelectedHandler( Object target, String </p>
		<p>methodName )<br /> {<br />  delegate = (IWidgetSelectedDelegate) </p>
		<p>MethodDelegate.create( target,<br />    methodName, </p>
		<p>IWidgetSelectedDelegate.class );<br /> }</p>
		<p> public void widgetDefaultSelected( SelectionEvent e )<br /> {<br /> }</p>
		<p> public void widgetSelected( SelectionEvent e )<br /> {<br />  delegate.invoke( e );<br /> }</p>
		<p> public void invoke( SelectionEvent e )<br /> {<br /> }</p>
		<p> public interface IWidgetSelectedDelegate<br /> {<br />  void invoke( SelectionEvent e );<br /> }</p>
		<p> private IWidgetSelectedDelegate delegate;<br />}</p>
		<p>这个接口虽然只有外部类用到，但是必须声明为public的，否则运行会出错（我想大概是因为代码生成以后还是外部类，需要公开访问权限）。为了简化调用，再声明一个处理事件的辅助类EventHandler，专门管理将各种事件转发到相应的Handler的工作：</p>
		<p>public class EventHandler<br />{<br /> public EventHandler( Object target )<br /> {<br />  this.target = target;<br /> }</p>
		<p> public void handleSelected( Button btn, String methodName )<br /> {<br />  btn.addSelectionListener( new </p>
		<p>WidgetSelectedHandler( target, methodName ) );<br /> }<br /> private Object target;<br />}</p>
		<p>这样，在窗口中就可以简单的如下处理事件：<br />public MainShell extends Shell()<br />{<br />  public MainShell( Display display )<br /> {<br />  ......<br />  handler = new EventHandler( this );<br />  handler.handleSelected( btn, "btn_clicked" );<br /> }</p>
		<p> public void btn_clicked( SelectionEvent e )<br /> {<br />  ...<br /> }<br />}</p>
		<p>这里还需要注意：1、任何事件处理方法必须声明为public的。这样似乎有违面向对象的封装原则，不过实际上并不会造成什么大问题。2、事件方法的签名必须和对应的事件方法相同。例如，widgetSelected方法有一个SelectionEvent参数，那么处理该事件的btn_clicked方法也必须有且只有这一个参数。如果写错了，那么运行的时候会抛出异常，说找不到指定的方法。这还是需要程序员的细心来保证。还算幸运的是出错的提示非常明显，不必担心使用了过度复杂的技术而找不到真正的出错点。<br /></p>
<img src ="http://www.blogjava.net/treenode/aggbug/55289.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/treenode/" target="_blank">TreeNode</a> 2006-06-27 11:29 <a href="http://www.blogjava.net/treenode/archive/2006/06/27/55289.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>内部类让我厌恶Java</title><link>http://www.blogjava.net/treenode/archive/2006/06/15/53098.html</link><dc:creator>TreeNode</dc:creator><author>TreeNode</author><pubDate>Thu, 15 Jun 2006 14:37:00 GMT</pubDate><guid>http://www.blogjava.net/treenode/archive/2006/06/15/53098.html</guid><wfw:comment>http://www.blogjava.net/treenode/comments/53098.html</wfw:comment><comments>http://www.blogjava.net/treenode/archive/2006/06/15/53098.html#Feedback</comments><slash:comments>26</slash:comments><wfw:commentRss>http://www.blogjava.net/treenode/comments/commentRss/53098.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/treenode/services/trackbacks/53098.html</trackback:ping><description><![CDATA[请比较一下这两段功能大致相同的代码。抛开语法的差别不论，你觉得哪种风格好？你愿意维护哪一段代码？<br /><br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">        b.addSelectionListener( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> SelectionAdapter()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> widgetSelected( SelectionEvent e )<br />            {<br />                Runnable longJob </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Runnable()<br />                {<br />                    </span><span style="color: rgb(0, 0, 255);">boolean</span><span style="color: rgb(0, 0, 0);">    done    </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">;<br />                    </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);">        id;<br /><br />                    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> run()<br />                    {<br />                        Thread thread </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Thread( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Runnable()<br />                        {<br />                            </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> run()<br />                            {<br />                                id </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nextId[</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">]</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">;<br />                                display.syncExec( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Runnable()<br />                                {<br />                                    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> run()<br />                                    {<br />                                        </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( text.isDisposed() )<br />                                            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />                                        text<br />                                                .append( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">\nStart long running task </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />                                                        </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> id );<br />                                    }<br />                                } );<br />                                </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> ( </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> i </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">; i </span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">100000</span><span style="color: rgb(0, 0, 0);">; i</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);"> )<br />                                {<br />                                    </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( display.isDisposed() )<br />                                        </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />                                    System.out<br />                                            .println( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">do task that takes a long time in a separate thread </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />                                                    </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> id );<br />                                }<br />                                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( display.isDisposed() )<br />                                    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />                                display.syncExec( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Runnable()<br />                                {<br />                                    </span><span style="color: rgb(0, 0, 255);">public</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> run()<br />                                    {<br />                                        </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( text.isDisposed() )<br />                                            </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />                                        text<br />                                                .append( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">\nCompleted long running task </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"><br />                                                        </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> id );<br />                                    }<br />                                } );<br />                                done </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">;<br />                                display.wake();<br />                            }<br />                        } );<br />                        thread.start();<br />                        </span><span style="color: rgb(0, 0, 255);">while</span><span style="color: rgb(0, 0, 0);"> ( </span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">done </span><span style="color: rgb(0, 0, 0);">&amp;&amp;</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">shell.isDisposed() )<br />                        {<br />                            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( </span><span style="color: rgb(0, 0, 0);">!</span><span style="color: rgb(0, 0, 0);">display.readAndDispatch() )<br />                                display.sleep();<br />                        }<br />                    }<br />                };<br />                BusyIndicator.showWhile( display, longJob );<br />            }<br />        } );<br /></span></div>另外一种：<br /><div style="border: 1px solid rgb(204, 204, 204); padding: 4px 5px 4px 4px; background-color: rgb(238, 238, 238); font-size: 13px; width: 98%;"><!--<br><br>Code highlighting produced by Actipro CodeHighlighter (freeware)<br>http://www.CodeHighlighter.com/<br><br>--><span style="color: rgb(0, 0, 0);">        </span><span style="color: rgb(0, 0, 255);">delegate</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> NotifyStartDelegate( </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> threadId );<br />        </span><span style="color: rgb(0, 0, 255);">delegate</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> NotifyFinishDelegate( </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> threadId );<br />        <br />        btnInvoke.Click </span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);"> BtnInvokeClick;<br />        <br />        </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> BtnInvokeClick(</span><span style="color: rgb(0, 0, 255);">object</span><span style="color: rgb(0, 0, 0);"> sender, System.EventArgs e)<br />        {<br />            text.Text </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">invoke long running job</span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">;<br />            <br />            Cursor </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Cursors.WaitCursor;<br />            Thread thread </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> Thread( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> ThreadStart(ThreadProc) );<br />            thread.Start();<br />        }<br />        <br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> ThreadProc()<br />        {<br />            </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> threadId </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> nextId </span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">;<br />            </span><span style="color: rgb(0, 0, 255);">bool</span><span style="color: rgb(0, 0, 0);"> done </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">false</span><span style="color: rgb(0, 0, 0);">;<br />            <br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( IsDisposed )<br />                </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />            <br />            Invoke( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> NotifyStartDelegate(notifyThreadStart), </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">object</span><span style="color: rgb(0, 0, 0);">[] { threadId } );<br />            </span><span style="color: rgb(0, 0, 255);">for</span><span style="color: rgb(0, 0, 0);"> ( </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> i</span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">; i</span><span style="color: rgb(0, 0, 0);">&lt;</span><span style="color: rgb(0, 0, 0);">100000</span><span style="color: rgb(0, 0, 0);">; i</span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);"> )<br />            {<br />                </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( IsDisposed )<br />                    </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />                Console.WriteLine( </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">do task that takes a long time in a separate thread </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> threadId );<br />            }<br />        <br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( IsDisposed )<br />                </span><span style="color: rgb(0, 0, 255);">return</span><span style="color: rgb(0, 0, 0);">;<br />            Invoke( </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> NotifyFinishDelegate(notifyThreadFinish), </span><span style="color: rgb(0, 0, 255);">new</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">object</span><span style="color: rgb(0, 0, 0);">[] { threadId } );<br />            done </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">true</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />        <br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> notifyThreadStart( </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> threadId )<br />        {<br />            text.Text </span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">\r\nStart long task </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> threadId;<br />            threadCount </span><span style="color: rgb(0, 0, 0);">++</span><span style="color: rgb(0, 0, 0);">;<br />        }<br />        <br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">void</span><span style="color: rgb(0, 0, 0);"> notifyThreadFinish( </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> threadId )<br />        {<br />            text.Text </span><span style="color: rgb(0, 0, 0);">+=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);">\r\nCompleted long running task </span><span style="color: rgb(0, 0, 0);">"</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">+</span><span style="color: rgb(0, 0, 0);"> threadId;    <br />            threadCount </span><span style="color: rgb(0, 0, 0);">--</span><span style="color: rgb(0, 0, 0);">;<br />            </span><span style="color: rgb(0, 0, 255);">if</span><span style="color: rgb(0, 0, 0);"> ( threadCount </span><span style="color: rgb(0, 0, 0);">==</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);"> )<br />                Cursor </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> Cursors.Default;<br />        }<br />        <br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> nextId </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br />        </span><span style="color: rgb(0, 0, 255);">private</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 255);">int</span><span style="color: rgb(0, 0, 0);"> threadCount </span><span style="color: rgb(0, 0, 0);">=</span><span style="color: rgb(0, 0, 0);"> </span><span style="color: rgb(0, 0, 0);">0</span><span style="color: rgb(0, 0, 0);">;<br /></span></div><br />
我在另一个地方也抱怨过：在所有我了解的语言特性里面，没有一种像Java内部类一样让我觉得反感——甚至到了恶心的地步。大多作B/S系统的Java程
序员可能不会有这样的感觉，因为那个领域基本上很少会用到这个概念。可是在C/S，不管用Swing还是SWT，内部类都是绕不过去的一座大山。在阅读Eclipse站点上许多代码示例以后，我终于有了痛苦到——一点也不夸张——想要作呕的地步。上面第一段代码就是让我感到窝心的代码之一（仅仅是其中之一，还不是最丑陋的）。我想，Java
语言的发明者大概从来就没写过桌面程序；他根本也不打算为这个领域的程序员提供一种比较好的事件回调机制。<br /><br />
内部类有什么问题呢？首先，你愿意在去看代码逻辑之前，先花上好几分钟去搞清楚“这个括号到底是和哪个配对”这种蠢问题吗？你不妨回头看看第一段的代码，想想这段其实相当简单的程序，是不是真的值得用这么多括号去考验你的智力。<br /><br />
内部类是对封装的严重破坏。它对外部类的任何私有变量都有完全的访问权限——如果你突然发现某个变量的内容不对劲了，你不能仅仅在setXXX里面加个断
点就指望能捕获到错误；真正的元凶可能是内部类里面的哪一句呢。如果内部类都非常简单，那倒也没什么。可是当内部类用来实现事件的时候，你就没法指望它一
直那么简单了。<br /><br />
内部类是测试的盲区。TDD总是说，要测试，测试，所有包含逻辑的类都应当通过充分的测试。可是内部类怎么测试？只要想想就能知道，大多数内部类是根本没法测试的，它和外部类实在是耦合的太紧密了。匿名内部类的问题更严重——它是绝对无法测试的。你怎么测试一个连名字都没有的方法？<br /><br />
不管有意无意，内部类在（至少我看到的）实践中事实上鼓励了不好的编程风格。就是说，它违背了DRY（Don't Repeat
Yourself）的原则。比如，button.addSelectionListener后面几乎总是跟着SelectionAdapter+括号+
widgetSelected原型再+一堆括号；Display.asyncExec后面总是要写上new Runnble()，void
run（），括号，等等。千篇一律的东西，可是又不得不写。而且，几乎没有什么好的办法可以改进！因为语法的规则要求你必须这样做。每天写这些无聊的东
西，你的话会不会烦？哦，工具是有的。可是工具只负责生成代码，以后的维护还是要你来做——不是么？<br /><img src ="http://www.blogjava.net/treenode/aggbug/53098.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/treenode/" target="_blank">TreeNode</a> 2006-06-15 22:37 <a href="http://www.blogjava.net/treenode/archive/2006/06/15/53098.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>SWT: 深入内幕之消息机制探秘（上篇）</title><link>http://www.blogjava.net/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.blogjava.net/treenode/archive/2006/06/03/50114.html</guid><wfw:comment>http://www.blogjava.net/treenode/comments/50114.html</wfw:comment><comments>http://www.blogjava.net/treenode/archive/2006/06/03/50114.html#Feedback</comments><slash:comments>9</slash:comments><wfw:commentRss>http://www.blogjava.net/treenode/comments/commentRss/50114.html</wfw:commentRss><trackback:ping>http://www.blogjava.net/treenode/services/trackbacks/50114.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: 本文试图透过SWT面向对象的封装，深入研究界面框架的构造中最复杂也可以说是最有趣的问题之一——即界面框架如何以面向对象的方式实现操作系统底层的消息机制。&nbsp;&nbsp;<a href='http://www.blogjava.net/treenode/archive/2006/06/03/50114.html'>阅读全文</a><img src ="http://www.blogjava.net/treenode/aggbug/50114.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.blogjava.net/treenode/" target="_blank">TreeNode</a> 2006-06-03 12:46 <a href="http://www.blogjava.net/treenode/archive/2006/06/03/50114.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>