下面通過(guò)一個(gè)例子,向大家展示一下用Groovy創(chuàng)建DSL的優(yōu)雅之處:
利用下面這種語(yǔ)法
??? person {
??????? name {
??????????? firstname 'Daniel'
??????????? lastname? 'Sun'
??????? }
??? }
或
??? person {
??????? name {
??????????? firstname = '山風(fēng)'
??????????? lastname? = '小子'
??????? }
??? }
創(chuàng)建一個(gè)Person對(duì)象。
def?createMetaClass(Class?clazz,?Closure?closure)?{
????/*?
????????為傳入的Class對(duì)象創(chuàng)建一個(gè)ExpandoMetaClass實(shí)例,但不將該ExpandoMetaClass實(shí)例注冊(cè)到MetaClassRegistry對(duì)象中
????*/
????def?emc?=?new?ExpandoMetaClass(clazz,?false)?
????/*
????????該closure用來(lái)初始化ExpandoMetaClass對(duì)象,這種寫法的思想與Template?Method?Pattern有異曲同工之妙
????*/
????closure(emc)?
????emc.initialize()?//?完成初始化過(guò)程
????return?emc
}
def?executeScript(dslScriptCode,?rootName,?closure)?{
????Script?dslScript?=?new?GroovyShell().parse(dslScriptCode)??//?讀取并解析DSL代碼,返回一個(gè)Script對(duì)象
????
????dslScript.metaClass?=?createMetaClass(dslScript.class)?{?emc?->
????/*
????????動(dòng)態(tài)新增一個(gè)名為"$rootName"的方法,注意"$rootName"的值決定于運(yùn)行時(shí),比如本例中的值為person
????*/
????????emc."$rootName"?=?closure?
????}
????
????return?dslScript.run()?//?執(zhí)行DSL代碼
}
class?Name?{
????String?firstname
????String?lastname
????String?toString()?{
????????"$firstname.$lastname"
????}
}
class?Person?{
????Name?name
????Person(name)?{
????????this.name?=?name
????}
????String?toString()?{
????????"My?name?is?$name"
????}
}
/*
PersonDelegate對(duì)象是下面作為參數(shù)傳入‘person方法’的closure的delegate,形象點(diǎn)說(shuō),closure就是那對(duì)大括號(hào){}以及大括號(hào)中的內(nèi)容
如果您對(duì)closure的delegate不太熟悉,可以參考在下的另一篇文章《Groovy解惑——closure中的delegate》(http://www.aygfsteel.com/BlueSUN/archive/2007/12/22/169580.html)
????person?{
????????
????}
*/
class?PersonDelegate?{
????def?person
????PersonDelegate(person)?{
????????this.person?=?person
????}
????/*?
????????關(guān)于methodMissing這一特殊方法,請(qǐng)參考在下的另一篇文章《Groovy高效編程——?jiǎng)討B(tài)改變對(duì)象的能力》(http://www.aygfsteel.com/BlueSUN/archive/2007/07/15/130318.html)
????*/
????def?methodMissing(String?name,?Object?args)?{
????????if?('name'?==?name?&&?args[0]?instanceof?Closure)?{
????????????def?nameClosure?=?args[0]
????????????/*?
????????????????給nameClosure的delegate賦值,nameClosure就是name旁邊的那個(gè)closure即一對(duì)大括號(hào){}以及大括號(hào)中的內(nèi)容
????????????*/
????????????nameClosure.delegate?=?new?NameDelegate(person)??
????????????nameClosure.resolveStrategy?=?Closure.DELEGATE_FIRST?//?指明closure中變量和方法的解析策略,本例選擇DELEGATE_FIRST
????????????nameClosure()
????????}
????}
????/*?
????????關(guān)于propertyMissing這一特殊方法,請(qǐng)參考在下的另一篇文章《Groovy高效編程——?jiǎng)討B(tài)改變對(duì)象的能力》(http://www.aygfsteel.com/BlueSUN/archive/2007/07/15/130318.html)
????*/
????def?propertyMissing(String?name)?{}
}
/*
類似于PersonDelegate,
NameDelegate對(duì)象是下面作為參數(shù)傳入‘name方法’的closure的delegate
????????name?{
????????????
????????}
*/
class?NameDelegate?{
????def?person
????NameDelegate(person)?{
????????this.person?=?person
????}
/*
????下面這些getter和setter是為了實(shí)現(xiàn)下面這種賦值而寫的:?firstname?=?'山風(fēng)'和lastname??=?'小子'
????person?{
????????name?{
????????????firstname?=?'山風(fēng)'
????????????lastname??=?'小子'
????????}
????}
*/
????def?getFirstname()?{
????????return?person.name.firstname
????}
????def?setFirstname(String?firstname)?{
????????person.name.firstname?=?firstname
????}
????def?getLastname()?{
????????return?person.name.lastname
????}
????def?setLastname(String?lastname)?{
????????person.name.lastname?=?lastname
????}
????
????def?methodMissing(String?name,?Object?args)?{
????????if?('firstname'?==?name)?{
????????????person.name.firstname?=?args[0]
????????}?else?if?('lastname'?==?name)?{
????????????person.name.lastname?=?args[0]
????????}
????}
????def?propertyMissing(String?name)?{}
}
/*
????在這篇文章中,演示了兩種賦值方式,各位可以根據(jù)自己的喜好選擇一種,我個(gè)人偏好第一種?:)
*/
//?本例DSL的第一種寫法
def?dslScriptCode?=?'''
????person?{
????????name?{
????????????firstname?'Daniel'
????????????lastname??'Sun'
????????}
????}
'''
def?scriptClosure?=?{?Closure?personClosure?->
????def?person?=?new?Person(new?Name())
????personClosure.delegate?=?new?PersonDelegate(person)
????personClosure.resolveStrategy?=?Closure.DELEGATE_FIRST
????personClosure()
????
????return?person
}
def?person?=?executeScript(dslScriptCode,?'person',?scriptClosure)
println?person
//?本例DSL的第二種寫法
def?dslScriptCode2?=?'''
????person?{
????????name?{
????????????firstname?=?'山風(fēng)'
????????????lastname??=?'小子'
????????}
????}
'''
def?scriptClosure2?=?{?Closure?personClosure?->
????def?person2?=?new?Person(new?Name())
????personClosure.delegate?=?new?PersonDelegate(person2)
????personClosure.resolveStrategy?=?Closure.DELEGATE_FIRST
????personClosure()
????
????return?person2
}
def?person2?=?executeScript(dslScriptCode2,?'person',?scriptClosure2)
println?person2
????/*?
????????為傳入的Class對(duì)象創(chuàng)建一個(gè)ExpandoMetaClass實(shí)例,但不將該ExpandoMetaClass實(shí)例注冊(cè)到MetaClassRegistry對(duì)象中
????*/
????def?emc?=?new?ExpandoMetaClass(clazz,?false)?
????/*
????????該closure用來(lái)初始化ExpandoMetaClass對(duì)象,這種寫法的思想與Template?Method?Pattern有異曲同工之妙
????*/
????closure(emc)?
????emc.initialize()?//?完成初始化過(guò)程
????return?emc
}
def?executeScript(dslScriptCode,?rootName,?closure)?{
????Script?dslScript?=?new?GroovyShell().parse(dslScriptCode)??//?讀取并解析DSL代碼,返回一個(gè)Script對(duì)象
????
????dslScript.metaClass?=?createMetaClass(dslScript.class)?{?emc?->
????/*
????????動(dòng)態(tài)新增一個(gè)名為"$rootName"的方法,注意"$rootName"的值決定于運(yùn)行時(shí),比如本例中的值為person
????*/
????????emc."$rootName"?=?closure?
????}
????
????return?dslScript.run()?//?執(zhí)行DSL代碼
}
class?Name?{
????String?firstname
????String?lastname
????String?toString()?{
????????"$firstname.$lastname"
????}
}
class?Person?{
????Name?name
????Person(name)?{
????????this.name?=?name
????}
????String?toString()?{
????????"My?name?is?$name"
????}
}
/*
PersonDelegate對(duì)象是下面作為參數(shù)傳入‘person方法’的closure的delegate,形象點(diǎn)說(shuō),closure就是那對(duì)大括號(hào){}以及大括號(hào)中的內(nèi)容
如果您對(duì)closure的delegate不太熟悉,可以參考在下的另一篇文章《Groovy解惑——closure中的delegate》(http://www.aygfsteel.com/BlueSUN/archive/2007/12/22/169580.html)
????person?{
????????

????}
*/
class?PersonDelegate?{
????def?person
????PersonDelegate(person)?{
????????this.person?=?person
????}
????/*?
????????關(guān)于methodMissing這一特殊方法,請(qǐng)參考在下的另一篇文章《Groovy高效編程——?jiǎng)討B(tài)改變對(duì)象的能力》(http://www.aygfsteel.com/BlueSUN/archive/2007/07/15/130318.html)
????*/
????def?methodMissing(String?name,?Object?args)?{
????????if?('name'?==?name?&&?args[0]?instanceof?Closure)?{
????????????def?nameClosure?=?args[0]
????????????/*?
????????????????給nameClosure的delegate賦值,nameClosure就是name旁邊的那個(gè)closure即一對(duì)大括號(hào){}以及大括號(hào)中的內(nèi)容
????????????*/
????????????nameClosure.delegate?=?new?NameDelegate(person)??
????????????nameClosure.resolveStrategy?=?Closure.DELEGATE_FIRST?//?指明closure中變量和方法的解析策略,本例選擇DELEGATE_FIRST
????????????nameClosure()
????????}
????}
????/*?
????????關(guān)于propertyMissing這一特殊方法,請(qǐng)參考在下的另一篇文章《Groovy高效編程——?jiǎng)討B(tài)改變對(duì)象的能力》(http://www.aygfsteel.com/BlueSUN/archive/2007/07/15/130318.html)
????*/
????def?propertyMissing(String?name)?{}
}
/*
類似于PersonDelegate,
NameDelegate對(duì)象是下面作為參數(shù)傳入‘name方法’的closure的delegate
????????name?{
????????????

????????}
*/
class?NameDelegate?{
????def?person
????NameDelegate(person)?{
????????this.person?=?person
????}
/*
????下面這些getter和setter是為了實(shí)現(xiàn)下面這種賦值而寫的:?firstname?=?'山風(fēng)'和lastname??=?'小子'
????person?{
????????name?{
????????????firstname?=?'山風(fēng)'
????????????lastname??=?'小子'
????????}
????}
*/
????def?getFirstname()?{
????????return?person.name.firstname
????}
????def?setFirstname(String?firstname)?{
????????person.name.firstname?=?firstname
????}
????def?getLastname()?{
????????return?person.name.lastname
????}
????def?setLastname(String?lastname)?{
????????person.name.lastname?=?lastname
????}
????
????def?methodMissing(String?name,?Object?args)?{
????????if?('firstname'?==?name)?{
????????????person.name.firstname?=?args[0]
????????}?else?if?('lastname'?==?name)?{
????????????person.name.lastname?=?args[0]
????????}
????}
????def?propertyMissing(String?name)?{}
}
/*
????在這篇文章中,演示了兩種賦值方式,各位可以根據(jù)自己的喜好選擇一種,我個(gè)人偏好第一種?:)
*/
//?本例DSL的第一種寫法
def?dslScriptCode?=?'''
????person?{
????????name?{
????????????firstname?'Daniel'
????????????lastname??'Sun'
????????}
????}
'''
def?scriptClosure?=?{?Closure?personClosure?->
????def?person?=?new?Person(new?Name())
????personClosure.delegate?=?new?PersonDelegate(person)
????personClosure.resolveStrategy?=?Closure.DELEGATE_FIRST
????personClosure()
????
????return?person
}
def?person?=?executeScript(dslScriptCode,?'person',?scriptClosure)
println?person
//?本例DSL的第二種寫法
def?dslScriptCode2?=?'''
????person?{
????????name?{
????????????firstname?=?'山風(fēng)'
????????????lastname??=?'小子'
????????}
????}
'''
def?scriptClosure2?=?{?Closure?personClosure?->
????def?person2?=?new?Person(new?Name())
????personClosure.delegate?=?new?PersonDelegate(person2)
????personClosure.resolveStrategy?=?Closure.DELEGATE_FIRST
????personClosure()
????
????return?person2
}
def?person2?=?executeScript(dslScriptCode2,?'person',?scriptClosure2)
println?person2
運(yùn)行結(jié)果:
My?name?is?Daniel.Sun
My?name?is?山風(fēng).小子
My?name?is?山風(fēng).小子
附:朝花夕拾——Groovy & Grails