這裡所說的接口類型,在Java語言和Groovy語言中,當然是既包括了基類類型和接口。所謂"接口類型的動態性",指的是在運行期內給基類或接口動態的添加方法,使得基類以及它的子類、接口的實現,都能訪問這些方法。
這個功能一向是我比較感興趣的一個功能。因為我們在編程的實踐中,會使用各種各樣的應用API,還有JDK,在使用它們的過程中,可能有一些接口及它們的子類我們會經常使用到,但是在使用的過程中,我們又感到非常的不方便。這時候,我們可以使用Categories機制來對我們所使用的類進行擴充功能,但如果一個類有很幾個子類或者一個接口有好幾個實現,對於所有的子類或實現,我們都希望進行相同的功能擴充。那麼,如果我們使用Categories機制的話,我們就不得不對所有的子類或實現進行依次擴充。這就造成了重復性的勞動。
而我們使用ExpandoMetaClass機制的話,則只需要對基類或者接口進行功能擴充,那麼所有的子類或實現都能夠得到該功能。這是多麼的激動人心啊!
首先,我們來看一個基類和它的子類的例子。
我們已經擁有了如下的一個基類:
class A
{
def afuction()
{
println 'a'
}
}
同時,我們也已經有了好幾個它的子類,下面就是一個例子:
class B extends A
{
def bfuction()
{
println 'b'
}
}
現在,我們希望給A類在運行期內增加一個方法,同時,B類也擁有了該方法。
首先,使得ExpandoMetaClass enabled globally:
ExpandoMetaClass.enableGlobally()
接著,我們給A類增加方法:
A.metaClass."aAndb" = {
->
println 'a and b'
}
下面,我們就可以測試了:
def a = new A()
a.aAndb()
def b = new B()
b.aAndb()
運行結果為:
a and b
a and b
果然達到了我們的要求。一切都很簡單,但需要注意的是在給基類添加方法之前,一定要加上"ExpandoMetaClass.enableGlobally()",否則,就會報告如下的錯誤:
Exception in thread "main" groovy.lang.MissingMethodException: No signature of method: mop.B.aAndb() is applicable for argument types: () values: {}
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:54)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:59)
at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.invokeMethodN(ScriptBytecodeAdapter.java:169)
at mop.A.invokeMethod(Testor3.groovy)
同樣,我們也可以對一個接口的所有的實現進行功能擴展。比如,我們想對List接口進行功能擴展,舉一個簡單的例子--我們想獲取一個List對象的倒序List對象,就可以進行如下的編程:
ExpandoMetaClass.enableGlobally()
List.metaClass.reversed = {
->
def rl = []
for(int i in (delegate.size()-1..0))
{
rl << delegate.getAt(i)
}
rl
}
跟基類的原理一樣,我們是在接口上添加功能。下面我們就可以進行測試了:
def list = [1,2,3]
list = list.reversed()
println list
運行的結果為:
[3, 2, 1]
一切也都顯得比較簡單,唯一需要注意的是,記得加上如下的語句:
ExpandoMetaClass.enableGlobally()
否則,同樣會報"MissingMethodException"的錯誤。