公众号「稀有猿诉」 原文链接 Understanding Kotlin Based DSL
DSL Domain Specific Langauge是解决特定领域内问题的编程语言,它的特点通常是简洁,虽不通用,但可读性强,呈描述式和声明式,比较典型的例子就是SQL语句和正则表达式,以及一些文本处理工具如Sed和AWK。与之对应的就是通用编程语言GPL General Purpose Language,能解决几乎所有的计算机问题,没有为特定领域进行定制,但语句可读性远不及DSL,它们的语句一般都是命令式的,如熟悉的C/C++, Java和Python等。
GPL中的DSL痛点
DSL的优点是声明式的,描述式的 ,并不在意具体细节的实现,比如像SQL语句,我只关心我想要什么,具体如何实现的是底下工具的事情:
SQL
select (id, name, address)
where name = "John" and age <= 10
from classlist
但,当在GPL,通用编程语言中解决DSL问题时,就会很蛋疼,在任何一个编程语言中实现一个SQL查询 的接口都会相当的笨拙和难用,要么需要创建很多个对象,要么需要传递一大堆令人费解的参数:
Java
Cursor cursor = query(uri, projects, where, whereArgs, sortby);
可读性非常的差,假如能写成DSL那样,可读性会大大的增强。
DSL式的API
在Kotlin中,可以写成这样:
kotlin
query {
from "classlist"
where {
"name" eq "John"
"age" lessEq 10
}
}
可读性大大加强,这样的API使用起来也会如丝般顺滑,因为它符合DSL:描述性的,声明式的,不关心具体实现细节,只关注想要什么。
背后原理
Kotlin借助尾部lambda,infix函数,扩展函数。整体来就其实是一个函数调用,因为Kotlin函数最后一个参数如果是lambda时可以写在函数调用之外,所以,一层一层的花括号,其实就是函数调用。
再借助扩展函数和infix函数,可以把另外一些函数调用写成DSL式,比如像二进制按位或运算a or b等同于a.or(b),这也是一个函数调用,但可读性大大加强。可以像写不作文一样的来写代码。
总之,见到DSL式的语句时不用惊慌,它是合法的Kotlin函数调用,把它理解成为函数调用就可以了。
合理使用
虽然DSL式的API能大大提高可读性,像真正的DSL一样去使用,但也要注意合理使用,不能滥用。我们要正向的解决问题,当遇到特定领域(Domain)的问题时,就可以定义和实现出一套符合DSL的API。也就是说我们要利用Kotlin语言提供的能力来实现DSL式的API去解决特定领域的问题。就像Android的布局,就可以定义出一套DSL式的API,这就是当时比较火的anko(现已废弃了)和现在的Compose,以及像涉及HTML,SQL的等特定领域问题时。
但不能反过来,为了写成DSL式,而去把所有的API都搞成DSL那样,比如把一些常规的操作像网络,像文件操作等都搞成那样,那就纯属滥用了。
参考资料
- Type-safe builders
- Building DSLs in Kotlin
- API设计:用流畅接口构造内部DSL
- Kotlin之美------DSL篇
- Mastering Kotlin DSL In Android - Step By Step Guide
- How do Kotlin DSL libraries work?
欢迎搜索并关注 公众号「稀有猿诉」 获取更多的优质文章!
原创不易,「打赏」 ,「点赞」 ,「在看」 ,「收藏」 ,「分享」 总要有一个吧!