1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        使用Groovy構(gòu)建DSL

        共 3268字,需瀏覽 7分鐘

         ·

        2021-03-07 11:52

        DSL(Domain Specific Language)官方定義為:針對某一領(lǐng)域,具有受限表達(dá)性的一種計算機(jī)程序設(shè)計語言。

        常用于聚焦指定的領(lǐng)域或問題,這就要求 DSL 具備強(qiáng)大的表現(xiàn)力,同時在使用起來要簡單。由于其使用簡單的特性,DSL 通常不會像 Java,C++等語言將其應(yīng)用于一般性的編程任務(wù)。

        對于 Groovy 來說,一個偉大的 DSL 產(chǎn)物就是新一代構(gòu)建工具——Gradle,接下來讓我們看下有哪些特性來支撐Groovy方便的編寫DSL:

        一、原理

        1、閉包

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

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

        比如:

        //閉包賦值def closure = {    printf("hello")}//調(diào)用closure()

        2、括號語法

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

        def add(number) { 1 + number }
        //DSL調(diào)用def res = add 1println res


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

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

        3、無參方法調(diào)用

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

        def getTotal() { println "Total" }
        //DSL調(diào)用total

        4、MOP

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

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

        常用的方法有:

        • invokeMethod()

        • setProperty()

        • hasProperty()

        • methodMissing()

        以下是一個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)前腳本屬于哪個Delegate,從而執(zhí)行相應(yīng)的腳本命令,也使IDE有自動提示的功能:

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

        腳本:

        import dsl.groovy.SetNameDelegateimport groovy.transform.BaseScript
        @BaseScript DslDelegate _
        setName("name")

        6、閉包委托

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

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

        //定義二級閉包格式class Conf{    String name    int age
        Conf name(String name) { this.name = name return this }
        Conf age(int age) { this.age = age return this }}
        //定義一級閉包格式,即腳本的格式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ù)庫或配置中,這時候就需要先加載腳本再執(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()

        二、總結(jié)

        通過以上的原理,你應(yīng)該能設(shè)計出自己的DSL了,通多DSL可以設(shè)計出非常簡潔的API給用戶,在執(zhí)行的時候調(diào)用DSL內(nèi)部的復(fù)雜功能,這些功能的背后邏輯隱藏在了自己編寫的Delegate中。

        為了加深印象,我寫了個小的開源項(xiàng)目,把上面知識點(diǎn)串起來,構(gòu)建了一個較完整的流程,如果還有什么不懂的地方,歡迎留言交流。

        項(xiàng)目地址:https://github.com/sofn/dsl-groovy

        本文作者:木小豐,美團(tuán)Java高級工程師,關(guān)注架構(gòu)、軟件工程、全棧等,不定期分享軟件研發(fā)過程中的實(shí)踐、思考。

        推薦閱讀:

        華為前中央硬件院院長李靖:做一家500億美金的公司

        華為內(nèi)部幾近滿分的項(xiàng)目管理PPT,牛逼了

        華為15年招聘經(jīng)驗(yàn)總結(jié):可用之才,必備5個特質(zhì)

        不是你需要中臺,而是一名合格的架構(gòu)師(附各大廠中臺建設(shè)PPT)

        世界的真實(shí)格局分析,地球人類社會底層運(yùn)行原理

        世界先進(jìn)生產(chǎn)力的入門法則,如何精準(zhǔn)識人


        瀏覽 21
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        評論
        圖片
        表情
        推薦
        點(diǎn)贊
        評論
        收藏
        分享

        手機(jī)掃一掃分享

        分享
        舉報
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            美女黄网站免费 | 九一精品视频 | 亚洲日韩一区 | 高潮喷水在线 | 日韩国产精品一级毛片 | 小泬BBBBBB免费看 | 日韩中文无码电影 | 丁香色婷婷五月 | 王雨纯脱得连奶罩都不剩 | 一区二区性虐 |