利用Groovy與生俱來的動態(tài)特性,創(chuàng)建DSL(Domain Specific Language)是一件十分容易的事情。
下面通過一個例子,向大家展示一下用Groovy創(chuàng)建DSL的優(yōu)雅之處:
利用下面這種語法
??? person {
??????? name {
??????????? firstname 'Daniel'
??????????? lastname? 'Sun'
??????? }
??? }
或
??? person {
??????? name {
??????????? firstname = '山風(fēng)'
??????????? lastname? = '小子'
??????? }
??? }
創(chuàng)建一個Person對象。
def?createMetaClass(Class?clazz,?Closure?closure)?{
????/*?
????????為傳入的Class對象創(chuàng)建一個ExpandoMetaClass實例,但不將該ExpandoMetaClass實例注冊到MetaClassRegistry對象中
????*/
????def?emc?=?new?ExpandoMetaClass(clazz,?false)?
????/*
????????該closure用來初始化ExpandoMetaClass對象,這種寫法的思想與Template?Method?Pattern有異曲同工之妙
????*/
????closure(emc)?
????emc.initialize()?//?完成初始化過程
????return?emc
}
def?executeScript(dslScriptCode,?rootName,?closure)?{
????Script?dslScript?=?new?GroovyShell().parse(dslScriptCode)??//?讀取并解析DSL代碼,返回一個Script對象
????
????dslScript.metaClass?=?createMetaClass(dslScript.class)?{?emc?->
????/*
????????動態(tài)新增一個名為"$rootName"的方法,注意"$rootName"的值決定于運行時,比如本例中的值為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對象是下面作為參數(shù)傳入‘person方法’的closure的delegate,形象點說,closure就是那對大括號{}以及大括號中的內(nèi)容
如果您對closure的delegate不太熟悉,可以參考在下的另一篇文章《Groovy解惑——closure中的delegate》(http://m.tkk7.com/BlueSUN/archive/2007/12/22/169580.html)
????person?{
????????
????}
*/
class?PersonDelegate?{
????def?person
????PersonDelegate(person)?{
????????this.person?=?person
????}
????/*?
????????關(guān)于methodMissing這一特殊方法,請參考在下的另一篇文章《Groovy高效編程——動態(tài)改變對象的能力》(http://m.tkk7.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旁邊的那個closure即一對大括號{}以及大括號中的內(nèi)容
????????????*/
????????????nameClosure.delegate?=?new?NameDelegate(person)??
????????????nameClosure.resolveStrategy?=?Closure.DELEGATE_FIRST?//?指明closure中變量和方法的解析策略,本例選擇DELEGATE_FIRST
????????????nameClosure()
????????}
????}
????/*?
????????關(guān)于propertyMissing這一特殊方法,請參考在下的另一篇文章《Groovy高效編程——動態(tài)改變對象的能力》(http://m.tkk7.com/BlueSUN/archive/2007/07/15/130318.html)
????*/
????def?propertyMissing(String?name)?{}
}
/*
類似于PersonDelegate,
NameDelegate對象是下面作為參數(shù)傳入‘name方法’的closure的delegate
????????name?{
????????????
????????}
*/
class?NameDelegate?{
????def?person
????NameDelegate(person)?{
????????this.person?=?person
????}
/*
????下面這些getter和setter是為了實現(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ù)自己的喜好選擇一種,我個人偏好第一種?:)
*/
//?本例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
運行結(jié)果:
My?name?is?Daniel.Sun
My?name?is?山風(fēng).小子
附:
朝花夕拾——Groovy & Grails
posted on 2008-05-17 00:38
山風(fēng)小子 閱讀(5703)
評論(1) 編輯 收藏 所屬分類:
Groovy & Grails