用Kotlin构建内部DSL

正文

通过Kotlin来构建内部DSL,所需的前置知识点有:

  1. 如果lambda表达式作为函数的最后一个参数,可以把放到括号外
  2. lambda表达式&高阶函数
  3. 带接收者的lambda表达式(对lambda表达式的拓展)
  4. 拓展函数和拓展属性

因此假设我们都了解并能熟练使用上面的知识点,那么Kotlin构建DSL也就成功了一半,我们来看一个例子:

我有一个书房,书房里有一张桌子和装有若干书籍的书柜

用dsl表达效果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
private fun dslTest2(){
createHouse().studyRoom {
desk {
width = 50
length = 100
heigth = 75
}

bookShelf {
book {
title = "Kotlin实战"
page {
index = 40
}
}

book {
title = "Effective Java"
}
}
}
}

上述实现代码如下:

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
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
open class Node public constructor(var name: String) {

fun <T : Node> init(child: T, action: T.() -> Unit) {
child.action()
}

}

class BookShelf : Node("BookShelf") {
fun book(action: Book.() -> Unit) = init(Book(), action)
}

class Desk : Node("Desk") {
var width: Int = 0
var heigth: Int = 0
var length: Int = 0

override fun toString(): String {
return "Desk(width=$width, heigth=$heigth, length=$length)"
}

}

class Page : Node("Page") {
var index: Int = 1

override fun toString(): String {
return "Page(index=$index)"
}
}

class Book : Node("Book") {
var title: String = ""
var count: Int = 1

fun page(action: Page.() -> Unit) = init(Page(), action)

override fun toString(): String {
return "Book(title='$title', count=$count)"
}
}

class StudyRoom : Node("StudyRoom") {

fun bookShelf(action: BookShelf.() -> Unit) = init(BookShelf(), action)

fun desk(action: Desk.() -> Unit) = init(Desk(), action)
}

class House : Node("House") {
fun studyRoom(action: StudyRoom.() -> Unit) = init(StudyRoom(), action)

}

fun createHouse(): House = House()

参考资料