当前位置:   article > 正文

Kotlin:函数DSL实战_kotlin 1.days ago

kotlin 1.days ago

DSL(domain specific language),即领域专用语言:专门解决某一特定问题的计算机语言,比如大家耳熟能详的 SQL 和正则表达式
Kotlin DSL的简单定义:“使用 Kotlin 语言开发的,解决特定领域问题,具备独特代码结构的API 。”

扩展函数/属性

假设我们想获取昨天的日期,昨天相对于今天来说也就是一天前,那么获取这个方法的DSL写法就应该是:

 val yesterday = 1.days.ago 
  • 1

由上面的结构,我们可以设计扩展函数如下:

fun Int.days() = Period.ofDays(this)
fun Period.ago() = LocalDate.now() - this

//调用
val yesterday = 1.days().ago()
  • 1
  • 2
  • 3
  • 4
  • 5

我们只需要修改扩展函数为扩展属性,即可实现最终效果,如下:

val Int.days: Period
    get() = Period.ofDays(this)

val Period.ago: LocalDate
    get() = LocalDate.now() - this

//调用
val yesterday = 1.days.ago
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

因此Kotlin DSL有一个显著的特征:近似于口语(个人理解)。

定义一个类及接口

我们先定义一个包含多个方法接口,和需要使用该接口的类。一步步来展示在Kotlin如何使用DSL。

interface Listener {
    fun onStart()

    fun onNext()

    fun onComplete(result:String)
}

class Work {
    private var listener: Listener? = null
    fun start() {
        listener?.run {
            onStart()
            onNext()
            onComplete("onComplete")
        }
    }

    fun addListener(listener: Listener) {
        //接口赋值
        this.listener = listener
    }
    //doSomething
}doSomething
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25

基本使用

如下代码,便是这个接口最基本的使用。

    val  work = Work()
    work.addListener(object :Listener{
        override fun onStart() {

        }

        override fun onNext() {

        }

        override fun onComplete(result:String) {

        }
    })
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14

思考:日常开发中接口中的每一个方法都不一定必须会使用。如上频繁使用该接口,但是我们很多时候只关心onComplete方法中的回调值,所以每次都书写onStart,onNext会造成很多的代码冗余。怎么去解决这个问题呢?

继承

在Java开发中,我们通常会使用继承写一个中间类,来避免接口方法过多的情况。如下:

open class AListener : Listener {
    override fun onStart() {

    }

    override fun onNext() {

    }

    override fun onComplete(result: String) {

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

这时我们需要哪个方法,重写哪个方法即可:

  work.addListener(object : AListener() {
        override fun onComplete(result: String) {
            super.onComplete(result)
        }
    })
  • 1
  • 2
  • 3
  • 4
  • 5

高阶函数

学习了Kotlin之后,我们发现函数可以作为另一个函数的参数(此时这个函数叫高阶函数),我们可以把上面接口方法的作为函数参数传给扩展函数,简化调用:

//别名
typealias onEmpty = () -> Unit
typealias onResult = (String) -> Unit

inline fun Work.addListenerHigh(
        crossinline onStart: onEmpty = {},
        crossinline onNext: onEmpty = {},
        crossinline onComplete: onResult = { result -> }) {
    this.addListener(object : Listener {
        override fun onStart() {
            onStart.invoke()
        }

        override fun onNext() {
            onNext.invoke()
        }

        override fun onComplete(result: String) {
            onComplete.invoke(result)
        }
    })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

这时候我们只需要调用扩展函数,传入自己关注的接口方法即可。

 work.addListenerHigh(onComplete = { result: String -> {} })
  • 1

改造后的高阶函数,已经非常接近DSL结构,其实这里只是利用了Kotlin的具名参数的特性,并不是真正意义上的DSL结构。
接下来我们再进一步利用高阶含函数的特性将其改造成DSL结构。

DSL

我们先定义一个类,这个类的属性值都是上面接口对应的函数参数。

//别名
typealias onEmpty = () -> Unit
typealias onResult = (String) -> Unit

class ListenerDSL {
    var _onStart: onEmpty? = null
    var _onNext: onEmpty? = null
    var _onComplete: onResult? = null


    fun onStart(onEmpty: onEmpty) {
        _onStart = onEmpty
    }

    fun onNext(onEmpty: onEmpty) {
        _onNext = onEmpty
    }

    fun onComplete(onNext: onResult) {
        _onComplete = onNext
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

然后使用扩展函数的编写DSL:

fun Work.addListenerDSL(init: ListenerDSL.() -> Unit) {
    val listenerDSL = ListenerDSL()
    listenerDSL.init()
    this.addListener(object : Listener {
        override fun onStart() {
            listenerDSL._onStart?.invoke()
        }

        override fun onNext() {
            listenerDSL._onNext?.invoke()
        }

        override fun onComplete(result: String) {
            listenerDSL._onComplete?.invoke(result)
        }
    })
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

这个时候我们只需要调用:

   val work = Work()
    work.addListenerDSL {
        onStart { println("onStart") }
        onComplete { result -> println(result) }
    }
    work.start()
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

这个时候的写法就很赏心悦目了。

参考

https://www.jianshu.com/p/f5f0d38e3e44
https://www.jianshu.com/p/5b8c4cc38814

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/菜鸟追梦旅行/article/detail/538164
推荐阅读
相关标签
  

闽ICP备14008679号