溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊(cè)×
其他方式登錄
點(diǎn)擊 登錄注冊(cè) 即表示同意《億速云用戶服務(wù)條款》

Groovy中怎么構(gòu)建DSL

發(fā)布時(shí)間:2021-08-05 16:44:59 來源:億速云 閱讀:176 作者:Leah 欄目:編程語言

Groovy中怎么構(gòu)建DSL,針對(duì)這個(gè)問題,這篇文章詳細(xì)介紹了相對(duì)應(yīng)的分析和解答,希望可以幫助更多想解決這個(gè)問題的小伙伴找到更簡(jiǎn)單易行的方法。

一、原理

1、閉包

官方定義是“Groovy中的閉包是一個(gè)開放,匿名的代碼塊,可以接受參數(shù),返回值并分配給變量

簡(jiǎn)而言之,他說一個(gè)匿名的代碼塊,可以接受參數(shù),有返回值。在DSL中,一個(gè)DSL腳本就是一個(gè)閉包。

比如:

//執(zhí)行一句話  
{ printf 'Hello World' }                                   
    
//閉包有默認(rèn)參數(shù)it,且不用申明      
{ println it }                   

//閉包有默認(rèn)參數(shù)it,申明了也無所謂                
{ it -> println it }      
    
// name是自定義的參數(shù)名  
{ name -> println name }                 

 //多個(gè)參數(shù)的閉包
{ String x, int y ->                                
    println "hey ${x} the value is ${y}"    
}

每定義的閉包是一個(gè)Closure對(duì)象,我們可以把一個(gè)閉包賦值給一個(gè)變量,然后調(diào)用變量執(zhí)行

//閉包賦值
def closure = {
    printf("hello")
}
//調(diào)用
closure()
2、括號(hào)語法

當(dāng)調(diào)用的方法需要參數(shù)時(shí),Groovy 不要求使用括號(hào),若有多個(gè)參數(shù),那么參數(shù)之間依然使用逗號(hào)分隔;如果不需要參數(shù),那么方法的調(diào)用必須顯示的使用括號(hào)。

def add(number) { 1 + number }

//DSL調(diào)用
def res = add 1
println res

也支持級(jí)聯(lián)調(diào)用方式,舉例來說,a b c d 實(shí)際上就等同于 a(b).c(d)

//定義
total = 0
def a(number) {
    total += number
    return this
}
def b(number) {
    total *= number
    return this
}

//dsl
a 2 b 3
println total
3、無參方法調(diào)用

我們結(jié)合 Groovy 中對(duì)屬性的訪問就是對(duì) getXXX 的訪問,將無參數(shù)的方法名改成 getXXX 的形式,即可實(shí)現(xiàn)“調(diào)用無參數(shù)的方法不需要括號(hào)”的語法!比如:

def getTotal() { println "Total" }

//DSL調(diào)用
total
4、MOP

MOP:元對(duì)象協(xié)議。由 Groovy 語言中的一種協(xié)議。該協(xié)議的出現(xiàn)為元編程提供了優(yōu)雅的解決方案。而 MOP 機(jī)制的核心就是 MetaClass。

有點(diǎn)類似于 Java 中的反射,但是在使用上卻比 Java 中的反射簡(jiǎn)單的多。

常用的方法有:

  • invokeMethod()

  • setProperty()

  • hasProperty()

  • methodMissing()

以下是一個(gè)methodMissing的例子:

detailInfo = [:]

def methodMissing(String name, args) {
    detailInfo[name] = args
}

def introduce(closure) {
    closure.delegate = this
    closure()
    detailInfo.each {
        key, value ->
            println "My $key is $value"
    }
}

introduce {
    name "zx"
    age 18
}
5、定義和腳本分離

@BaseScript 需要在注釋在自定義的腳本類型變量上,來指定當(dāng)前腳本屬于哪個(gè)Delegate,從而執(zhí)行相應(yīng)的腳本命令,也使IDE有自動(dòng)提示的功能:

腳本定義
abstract class DslDelegate extends Script {
	def setName(String name){
        println name
    }
}

腳本:

import dsl.groovy.SetNameDelegate
import groovy.transform.BaseScript

@BaseScript DslDelegate _

setName("name")
6、閉包委托

使用以上介紹的方法,只能在腳本里執(zhí)行單個(gè)命令,如果想在腳本里執(zhí)行復(fù)雜的嵌套關(guān)系,比如Gradle中的dependencies,就需要@DelegatesTo支持了,@DelegatesTo執(zhí)行了腳本里定義的閉包用那個(gè)類來解析。

上面提到一個(gè)DSL腳本就是一個(gè)閉包,這里的DelegatesTo其實(shí)定義的是閉包里面的二級(jí)閉包的格式,當(dāng)然如果你樂意,可以無限嵌套定義。

//定義二級(jí)閉包格式
class Conf{
    String name
    int age

    Conf name(String name) {
        this.name = name
        return this
    }

    Conf age(int age) {
        this.age = age
        return this
    }
}

//定義一級(jí)閉包格式,即腳本的格式
String user(@DelegatesTo(Conf.class) Closure<Conf> closure) {
    Conf conf = new Conf()
    DefaultGroovyMethods.with(conf, closure)
    println "my name is ${conf.name} my age is ${conf.age}"
}

//dsl腳本
user{
    name "tom"
    age 12
}
7、加載并執(zhí)行腳本

腳本可以在IDE里直接執(zhí)行,大多數(shù)情況下DSL腳本都是以文本的形式存在數(shù)據(jù)庫或配置中,這時(shí)候就需要先加載腳本再執(zhí)行,加載腳本可以通過以下方式:

 CompilerConfiguration compilerConfiguration = new CompilerConfiguration();
 compilerConfiguration.setScriptBaseClass(DslDelegate.class.getName());
 GroovyShell shell = new GroovyShell(GroovyScriptRunner.class.getClassLoader());
 Script script = shell.parse(file);

給腳本傳參數(shù),并得到返回結(jié)果:

Binding binding = new Binding();
binding.setProperty("key", anyValue);
Object res = InvokerHelper.createScript(script.getClass(), binding).run()

關(guān)于Groovy中怎么構(gòu)建DSL問題的解答就分享到這里了,希望以上內(nèi)容可以對(duì)大家有一定的幫助,如果你還有很多疑惑沒有解開,可以關(guān)注億速云行業(yè)資訊頻道了解更多相關(guān)知識(shí)。

向AI問一下細(xì)節(jié)

免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。

AI