美文网首页
基于Kotlin DSL实现的声明式插件

基于Kotlin DSL实现的声明式插件

作者: 天天听听 | 来源:发表于2022-07-05 14:07 被阅读0次

    声明式编程

    声明式编程是近年来越来越火的编程思想。万物互联的发展,驱动分布式UI前进。而声明式编程,恰恰式实现分布式UI的最佳方式(个人观点,当前HW的分布式UI也是推荐使用声明式编程,Jetpack compose和flutter也是使用声明式编程)。本文不过多讨论分布式UI,只是介绍一种使用Kotlin DSL实现的声明式插件。其实这也是Compose的原理。

    什么是DSL

    全称是domin specific language(领域特定语言),是指专门用于实现某一领域难题的语言,常见的DSL包括SQL、HTML等。
    相对的另一种语言叫GPL,General Purpose Language(通用编程语言),我们熟悉的Java、Kotlin和Go等都是通用语言。
    Kotlin DSL是专门解决声明式编程的解决方案。

    为什么Kotlin能作为声明式编程的DSL

    高级函数

    高级函数运行将函数当前参数,并且如果函数是最后一个参数,可以使用小括号闭环函数,使用{}传递参数

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

    其中:after就是一个函数
    调用方式:

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

    扩展函数

    扩展函数,是可以通过给Class添加一个新的函数。上面的例子就是Project对象的一个函数。举一个简单的例子。

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

    给String声明一个扩展函数后,我们可以通过toAbsInt直接将字符串转换为绝对值数字。

    上下文传递

    after: Project.() -> Unit

    • after:参数名
    • ->:转向符,指向返回类型
    • Unit:返回类型
    • Project.() :一个Project的扩展函数,无参形式。这就是上下文传递的关键。传递一个扩展函数,使用时{}内的this对象就是Project。

    对比-普通高阶函数需要使用it传递上下文

    • 声明:Project是高阶函数的参数
    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.调用,就不像声明式编程。

    一个完整的声明式案例

    目的:声明式实现Maven仓库配置。
    修改前代码:

    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. 最外层声明一个仓库源集合:
    fun MavenRepository(
        publishingExtension: PublishingExtension,
        init: RepositoryHandler.() -> Unit
    ) {
        publishingExtension.repositories(init)
    }
    

    修改后调用:

    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
                    }
                }
            }
    

    这样外层就有点声明式的了,我们声明一个mavan的仓库源。但是里面的代码还是和声明式差很远。

    1. 声明一个远程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
        }
    }
    

    修改后调用:

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

    最后代码就这样写:

    1. 声明一个maven仓库源集合;
    2. 仓库源集合有两个仓库,一个release,一个snapshot。
      编程很简单,只需要声明即可。后面通过这样的思路,我们可以实现无代码编程。通过拖拽就可以完成maven仓库配置。
      --原来无代码可以这样来。

    相关文章

      网友评论

          本文标题:基于Kotlin DSL实现的声明式插件

          本文链接:https://www.haomeiwen.com/subject/oxqsbrtx.html