Kotlin-小抄(十)Kotlin創建DSL

DSL簡介

  • DSL (領域特定語言)指的是專注於特定問題領域的計算機語言,即對一個特定問題的方案模型更高層次的抽象表達,使之更加簡單易懂。
  • DSL只是問題解決方案模型的外部封裝,這個模型可能是一個API庫,也可能是一個完整的框架等
  • 在Android中比較典型的例子使用DSL框架Anko來替代傳統的xml(類似Flutter創建佈局的方式)如下代碼塊:
UI {
    // AnkoContext
    verticalLayout {
        padding = dip(30)
        var title = editText {
            // editText 視圖
            id = R.id.todo_title
            hintResource = R.string.title_hint
        }

        var content = editText {
            id = R.id.todo_content
            height = 400
            hintResource = R.string.content_hint
        }
        button {
            // button 視圖
            id = R.id.todo_add
            textResource = R.string.add_todo
            textColor = Color.WHITE
            setBackgroundColor(Color.DKGRAY)
            onClick { _ -> createTodoFrom(title, content) }
        }
    }
}

DSL種類

內部DSL
  • 內部DSL是指與項目中是使用的通用目的編程語言緊密相關的DSL
外部DSL
  • 外部DSL是從零開始構建的語言,需要實現語法分析器,外部DSL與通用編程語言(GPL)類似,但是外部DSL更加專注於特定領域,創建 外部DSL和創建一種通用的百年城語言的過程是類似的,可以是編譯型和解釋型

Kotlin中的DSL支持

實現原理
  • 擴展函數、擴展屬性
  • 帶接收者的Lambda表達式(高階函數)
  • invoke函數調用約定

實現集合類的流式Kotlin DSL

(可以模仿filter來實現)

// filter函數的入參是一個函數predicate:(T)->Boolean public inline fun <T> Iterable<T>.filter(predicate: (T) -> Boolean): List<T> {     return filterTo(ArrayList<T>(), predicate) }

fun <T : Comparable<T>> List<T>.sort() {
    Collections.sort(this) // this代表調用函數的對象
}

@Test
fun testSort() {
    val list = listOf(1,7,10,5,6)
    list.sort()
    print(list)  // [1, 5, 6, 7, 10]
}

實現SQL風格的集合類DSL

data class Student(var name: String, var sex: String, var score: Int)


fun <E> List<E>.select(): List<E> = this


fun <E> List<E>.where(prediction: (E) -> Boolean): List<E> {
    val list = this
    val result = arrayListOf<E>()
    for (e in list) {
        if (prediction(e)) {
            result.add(e)
        }
    }
    return result
}


fun <E> List<E>.and(prediction: (E) -> Boolean) : List<E> {
    return where(prediction)
}


@Test
fun testSql() {
    val students = listOf(
        Student("w", "M", 90),
        Student("e", "M", 80),
        Student("r", "M", 60),
        Student("t", "M", 80),
        Student("y", "F", 100)
    )


    val  queryResult = students.select()
        .where { it.score >= 80 }
        .and {it.sex == "M"}


    print(queryResult)
    // [Student(name=w, sex=M, score=90), Student(name=e, sex=M, score=80), Student(name=t, sex=M, score=80)]
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章