前面MOP——方法注入介紹了利用 MOP 對方法的調(diào)用進行注入,接下來要介紹利用 MOP 實現(xiàn)方法的合成。
合成:在運行期,根據(jù)輸入狀態(tài)的不同,動態(tài)的生成一個方法。
這里要注意的是:方法合成,在運行時動態(tài)的生成方法,看起來很智能,但是合成是有前提的,就是調(diào)用的方法的方法名必須要符合預先定義好的規(guī)范,才能生成。
同樣,這里要和前面的方法注入?yún)^(qū)分開:
方法的合成和注入看起來似乎相同,都是向類中添加方法,以擴展類的功能,但這里也是有區(qū)別的:
- 注入是已經(jīng)知道要注入的方法名了,是發(fā)生在編譯期的。
- 合成是在編譯期還不知道方法名,只有在調(diào)用的時候,發(fā)現(xiàn)并沒有對應的方法,所以動態(tài)的生成該方法,然后并調(diào)用。
合成強調(diào)的是在運行時,注入強調(diào)的是在編譯期;
實現(xiàn)方法合成有以下兩種方式:
- 使用 methodMissing 合成方法
- 使用 ExpandoMetaClass 合成方法
使用 methodMissing 合成方法
首先明確以下方法合成的使用場景:其發(fā)生在對象調(diào)用了一個自身并不存在的方法,正常情況下會拋出異常,但是我們想根據(jù)調(diào)用的方法動態(tài)去生成一個對應的方法并執(zhí)行。那么生成對應的方法這個步驟需要首先匯總到一個方法中——methodMissing,然后在該方法中,實現(xiàn)我們合成方法的邏輯。還是要注意,不是隨意調(diào)用一個方法都能合成的,沒有那么只能,必須符合預先設定好的規(guī)則。例如我們預先為一個人設定好其技能列表,但是不生成具體的方法,因為不知道外界會不會調(diào)用這些方法,如果全部實現(xiàn)一遍,到時候又可能用不到,所以需要在運行時,動態(tài)生成。
class Man {
def skills = ["run","sing","dance","talk"];
def methodMissing(String name,args){
if (skills.contains(name)){
println "I can " + name
}
}
}
man = new Man()
man.dance()
使用 ExpandoMetaClass 合成方法
當我們無法編輯類的源文件,那么就無法使用上面的方法了,對于這類情況,依然可以使用 ExpandoMetaClass 來合成方法,在MOP——方法注入中有提到過向 ExpandoMetaClass 中來注入方法,這里我們依然可以將 methodMissing 方法注入到 ExpandoMetaClass,從而實現(xiàn)方法合成。
class Man {
}
Man.metaClass.methodMissing = { String name,args ->
def skills = ["run","sing","dance","talk"];
if (skills.contains(name)){
println "I can " + name
}
}
man = new Man()
man.dance()
為具體實例合成方法
就像為具體實例注入方法一樣,我們也可以為具體實例合成方法,其代碼也是類似的
class Man{
}
def emc = new ExpandoMetaClass(Man)
emc.methodMissing = { String name,args ->
def skills = ["run","sing","dance","talk"];
if (skills.contains(name)){
println "I can " + name
}
}
emc.initialize()
def mike = new Man()
mike.metaClass = emc
mike.sing()