groovy提供了一些非常友善的方法來實作接口
隻有一個方法的接口可以使用閉包來實作,例如
<code>1</code>
<code>// a readable puts chars into a charbuffer and returns the count of chars added</code>
<code>2</code>
<code>def</code> <code>readable = { it.put(</code><code>"12 34"</code><code>.</code><code>reverse</code><code>()); </code><code>5</code> <code>} </code><code>as</code> <code>readable</code>
<code>3</code>
<code>4</code>
<code>// the scanner constructor can take a readable</code>
<code>5</code>
<code>def</code> <code>s = </code><code>new</code> <code>scanner(readable)</code>
<code>6</code>
<code>assert</code> <code>s.nextint() == </code><code>43</code>
當然也可以使用閉包來實作不止一個方法的接口.這個閉包将會被這個接口的所有的方法調用.例如:
<code>interface</code> <code>x {</code>
<code> </code><code>void</code> <code>f()</code>
<code> </code><code>void</code> <code>g(</code><code>int</code> <code>n)</code>
<code> </code><code>void</code> <code>h(string s, </code><code>int</code> <code>n)</code>
<code>}</code>
<code>7</code>
<code>x = {object[] args -> </code><code>println</code> <code>"method called with $args"</code><code>} </code><code>as</code> <code>x</code>
<code>8</code>
<code>x.f()</code>
<code>9</code>
<code>x.g(</code><code>1</code><code>)</code>
<code>10</code>
<code>x.h(</code><code>"hello"</code><code>,</code><code>2</code><code>)</code>
通常情況下,接口中都會包含多個方法,我們可以使用map來實作接口,比如:
<code>impl = [</code>
<code> </code><code>i: </code><code>10</code><code>,</code>
<code> </code><code>hasnext: { impl.i > </code><code>0</code> <code>},</code>
<code> </code><code>next: { impl.i-- },</code>
<code>]</code>
<code>iter = impl </code><code>as</code> <code>iterator</code>
<code>while</code> <code>( iter.hasnext() )</code>
<code> </code><code>println</code> <code>iter.next()</code>
請注意,這是一個有點做作的例子,但說明了這個概念。
你隻需要實作接口中會被調用的方法, 如果你調用了一個在map中并不存在的方法的話,那麼将會抛出nullpointerexception 異常。 例如:
<code>interface</code> <code>x</code>
<code>{ </code><code>void</code> <code>f(); </code><code>void</code> <code>g(</code><code>int</code> <code>n); </code><code>void</code> <code>h(string s, </code><code>int</code> <code>n); }</code>
<code>x = [ f: {</code><code>println</code> <code>"f called"</code><code>} ] </code><code>as</code> <code>x</code>
<code>//x.g() // npe here</code>
你能猜出下面的代碼做了什麼麼?
<code>x = { f: {</code><code>println</code> <code>"f called"</code><code>} } </code><code>as</code> <code>x</code>
我們在這裡定義的是一個閉包,一個标簽一個代碼塊,我們剛剛定義了一個每個接口方法都會調用的閉包, 一些語言使用{}來定義map,是以這可能誤導你,請記住在groovy中定義map使用[:]。
注意:使用as操作符需要你有一個你打算使用map實作的接口的靜态引用。如果你有一個代表你想實作的接口的java.lang.class 對象的引用,你就可以如同下面的方式一樣使用astype 方法:
<code>def</code> <code>loggerinterface = class.forname( </code><code>'my.loggerinterface'</code> <code>)</code>
<code>def</code> <code>logger = [</code>
<code> </code><code>log : { object[] params -> </code><code>println</code> <code>"log: ${params[0]}"</code><code>;</code><code>if</code><code>( params.length > </code><code>1</code> <code>) params[</code><code>1</code><code>].printstacktrace() },</code>
<code> </code><code>close : { </code><code>println</code> <code>"logger.close called"</code> <code>}</code>
<code> </code><code>].astype( loggerinterface )</code>
see also:
<a href="http://groovy.codehaus.org/developer+testing+using+closures+instead+of+mocks">developer testing using closures instead of mocks</a>