基于Kotlin DSL實(shí)現(xiàn)的聲明式插件

聲明式編程

聲明式編程是近年來(lái)越來(lái)越火的編程思想。萬(wàn)物互聯(lián)的發(fā)展恕汇,驅(qū)動(dòng)分布式UI前進(jìn)椰憋。而聲明式編程厅克,恰恰式實(shí)現(xiàn)分布式UI的最佳方式(個(gè)人觀點(diǎn),當(dāng)前HW的分布式UI也是推薦使用聲明式編程橙依,Jetpack compose和flutter也是使用聲明式編程)证舟。本文不過(guò)多討論分布式UI,只是介紹一種使用Kotlin DSL實(shí)現(xiàn)的聲明式插件窗骑。其實(shí)這也是Compose的原理女责。

什么是DSL

全稱是domin specific language(領(lǐng)域特定語(yǔ)言),是指專門用于實(shí)現(xiàn)某一領(lǐng)域難題的語(yǔ)言创译,常見的DSL包括SQL抵知、HTML等。
相對(duì)的另一種語(yǔ)言叫GPL软族,General Purpose Language(通用編程語(yǔ)言)刷喜,我們熟悉的Java、Kotlin和Go等都是通用語(yǔ)言立砸。
Kotlin DSL是專門解決聲明式編程的解決方案掖疮。

為什么Kotlin能作為聲明式編程的DSL

高級(jí)函數(shù)

高級(jí)函數(shù)運(yùn)行將函數(shù)當(dāng)前參數(shù),并且如果函數(shù)是最后一個(gè)參數(shù)颗祝,可以使用小括號(hào)閉環(huán)函數(shù)浊闪,使用{}傳遞參數(shù)

fun Project.after(after: Project.() -> Unit) {
    afterEvaluate(after)
}

其中:after就是一個(gè)函數(shù)
調(diào)用方式:

target.after {
            if (plugins.hasPlugin(ANDROID_LIBRARY)) {
                val android = extensions.getByType(LibraryExtension::class.java)
                AndroidPublication(android, extension, mavenPluginExtension)
            } else {
                JavaPublication(extension, mavenPluginExtension)
            }
        }

擴(kuò)展函數(shù)

擴(kuò)展函數(shù),是可以通過(guò)給Class添加一個(gè)新的函數(shù)螺戳。上面的例子就是Project對(duì)象的一個(gè)函數(shù)规揪。舉一個(gè)簡(jiǎn)單的例子。

fun String.toAbsInt():Int{
    return Math.abs(this.toInt())
}

給String聲明一個(gè)擴(kuò)展函數(shù)后温峭,我們可以通過(guò)toAbsInt直接將字符串轉(zhuǎn)換為絕對(duì)值數(shù)字猛铅。

上下文傳遞

after: Project.() -> Unit

  • after:參數(shù)名
  • ->:轉(zhuǎn)向符,指向返回類型
  • Unit:返回類型
  • Project.() :一個(gè)Project的擴(kuò)展函數(shù)凤藏,無(wú)參形式奸忽。這就是上下文傳遞的關(guān)鍵堕伪。傳遞一個(gè)擴(kuò)展函數(shù),使用時(shí){}內(nèi)的this對(duì)象就是Project栗菜。

對(duì)比-普通高階函數(shù)需要使用it傳遞上下文

  • 聲明:Project是高階函數(shù)的參數(shù)
fun Project.after(after: (Project) -> Unit) {

}
  • 使用:
target.after {
            if (it.plugins.hasPlugin(ANDROID_LIBRARY)) {
                val android = it.extensions.getByType(LibraryExtension::class.java)
                it.AndroidPublication(android, extension, mavenPluginExtension)
            } else {
                it.JavaPublication(extension, mavenPluginExtension)
            }
        }

如果存在it.調(diào)用欠雌,就不像聲明式編程。

一個(gè)完整的聲明式案例

目的:聲明式實(shí)現(xiàn)Maven倉(cāng)庫(kù)配置疙筹。
修改前代碼:

val mavenPluginExtension = target.extensions.getByType(PublishingExtension::class.java)
        mavenPluginExtension.repositories {
            it.maven { maven ->
                maven.name = MAVEN_SNAPSHOTS
                maven.isAllowInsecureProtocol = true
                maven.url = URI.create(REPOSITORY_SNAPSHOTS)
                maven.credentials { credentials ->
                    credentials.username = USER_NAME_SNAPSHOTS
                    credentials.password = PASSWORD_SNAPSHOTS
                }
            }
            it.maven { maven ->
                maven.name = MAVEN_RELEASE
                maven.isAllowInsecureProtocol = true
                maven.url = URI.create(REPOSITORY_RELEASE)
                maven.credentials { credentials ->
                    credentials.username = USER_NAME_RELEASE
                    credentials.password = PASSWORD_RELEASE
                }
            }
        }
  1. 最外層聲明一個(gè)倉(cāng)庫(kù)源集合:
fun MavenRepository(
    publishingExtension: PublishingExtension,
    init: RepositoryHandler.() -> Unit
) {
    publishingExtension.repositories(init)
}

修改后調(diào)用:

MavenRepository(mavenPluginExtension) {
            maven { maven ->
                maven.name = MAVEN_SNAPSHOTS
                maven.isAllowInsecureProtocol = true
                maven.url = URI.create(REPOSITORY_SNAPSHOTS)
                maven.credentials { credentials ->
                    credentials.username = USER_NAME_SNAPSHOTS
                    credentials.password = PASSWORD_SNAPSHOTS
                }
            }
            maven { maven ->
                maven.name = MAVEN_RELEASE
                maven.isAllowInsecureProtocol = true
                maven.url = URI.create(REPOSITORY_RELEASE)
                maven.credentials { credentials ->
                    credentials.username = USER_NAME_RELEASE
                    credentials.password = PASSWORD_RELEASE
                }
            }
        }

這樣外層就有點(diǎn)聲明式的了富俄,我們聲明一個(gè)mavan的倉(cāng)庫(kù)源。但是里面的代碼還是和聲明式差很遠(yuǎn)而咆。

  1. 聲明一個(gè)遠(yuǎn)程Maven
fun RepositoryHandler.RemoteMaven(
    mavenBean: MavenBean,
) {
    maven {
        it.create(mavenBean)
    }
}

fun MavenArtifactRepository.create(mavenBean: MavenBean) {
    name = mavenBean.name
    isAllowInsecureProtocol = true
    url = URI.create(mavenBean.url)
    credentials { credential ->
        credential.username = mavenBean.userName
        credential.password = mavenBean.password
    }
}

修改后調(diào)用:

MavenRepository(mavenPluginExtension) {
            RemoteMaven(mavenBean = releaseMavenBean)
            RemoteMaven(mavenBean = snapshotMavenBean)
        }

最后代碼就這樣寫:

  1. 聲明一個(gè)maven倉(cāng)庫(kù)源集合霍比;
  2. 倉(cāng)庫(kù)源集合有兩個(gè)倉(cāng)庫(kù),一個(gè)release暴备,一個(gè)snapshot悠瞬。
    編程很簡(jiǎn)單,只需要聲明即可涯捻。后面通過(guò)這樣的思路浅妆,我們可以實(shí)現(xiàn)無(wú)代碼編程。通過(guò)拖拽就可以完成maven倉(cāng)庫(kù)配置障癌。
    --原來(lái)無(wú)代碼可以這樣來(lái)凌外。
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市涛浙,隨后出現(xiàn)的幾起案子康辑,更是在濱河造成了極大的恐慌,老刑警劉巖蝗拿,帶你破解...
    沈念sama閱讀 206,839評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件晾捏,死亡現(xiàn)場(chǎng)離奇詭異蒿涎,居然都是意外死亡哀托,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,543評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門劳秋,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)仓手,“玉大人,你說(shuō)我怎么就攤上這事玻淑∷悦埃” “怎么了?”我有些...
    開封第一講書人閱讀 153,116評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵补履,是天一觀的道長(zhǎng)添坊。 經(jīng)常有香客問我,道長(zhǎng)箫锤,這世上最難降的妖魔是什么贬蛙? 我笑而不...
    開封第一講書人閱讀 55,371評(píng)論 1 279
  • 正文 為了忘掉前任雨女,我火速辦了婚禮,結(jié)果婚禮上阳准,老公的妹妹穿的比我還像新娘氛堕。我一直安慰自己,他們只是感情好野蝇,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,384評(píng)論 5 374
  • 文/花漫 我一把揭開白布讼稚。 她就那樣靜靜地躺著,像睡著了一般绕沈。 火紅的嫁衣襯著肌膚如雪锐想。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,111評(píng)論 1 285
  • 那天七冲,我揣著相機(jī)與錄音痛倚,去河邊找鬼。 笑死澜躺,一個(gè)胖子當(dāng)著我的面吹牛蝉稳,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播掘鄙,決...
    沈念sama閱讀 38,416評(píng)論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼耘戚,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了操漠?” 一聲冷哼從身側(cè)響起收津,我...
    開封第一講書人閱讀 37,053評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎浊伙,沒想到半個(gè)月后撞秋,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,558評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡嚣鄙,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,007評(píng)論 2 325
  • 正文 我和宋清朗相戀三年吻贿,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片哑子。...
    茶點(diǎn)故事閱讀 38,117評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡舅列,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出卧蜓,到底是詐尸還是另有隱情帐要,我是刑警寧澤,帶...
    沈念sama閱讀 33,756評(píng)論 4 324
  • 正文 年R本政府宣布弥奸,位于F島的核電站榨惠,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜赠橙,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,324評(píng)論 3 307
  • 文/蒙蒙 一伸蚯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧简烤,春花似錦剂邮、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,315評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至枉侧,卻和暖如春引瀑,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背榨馁。 一陣腳步聲響...
    開封第一講書人閱讀 31,539評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工憨栽, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人翼虫。 一個(gè)月前我還...
    沈念sama閱讀 45,578評(píng)論 2 355
  • 正文 我出身青樓屑柔,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親珍剑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子掸宛,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,877評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容