DSL
DSL
(Domain Specific Languages),特定领域语言,我们常见的在gradle
中依赖管理的配置:
repositories {
mavenCentral()
}
dependencies {
compile group: 'org.hibernate', name: 'hibernate-core', version: '3.6.7.Final'
testCompile group: 'junit', name: 'junit', version: '4.+'
}
这种语法就是DSL,我们可以用kotlin实现这样的功能效果,repositories
是一个函数,接收一个lambda
,lambda
里面又嵌套了另外一个函数.
官方也给出了一个关于DSL
的html例子,我会重新去实现一遍,代码的实现方式可能会略有差异:
fun main(vararg args:String) {
//函数调用
fun result() =
html {
head {
title {+"XML encoding with Kotlin"}
}
body {
h1 {+"XML encoding with Kotlin"}
p {+"this format can be used as an alternative markup to XML"}
// an element with attributes and text content
a(href = "https://kotlinlang.org") {+"Kotlin"}
// mixed content
p {
+"This is some"
b {+"mixed"}
+"text. For more see the"
a(href = "https://kotlinlang.org") {+"Kotlin"}
+"project"
}
// content generated by
p {
for (arg in args)
+arg
}
}
}
println(result().render())
代码实现:
abstract class Element(val tag:String){
val elements = mutableListOf<Element>();
open fun render():String{
val sb = StringBuilder()
sb.append("<${tag}>\n")
for (element in elements) {
sb.append("${element.render()}\n")
}
sb.append("</${tag}>\n")
return sb.toString();
}
operator fun String.unaryPlus() = this@Element.elements.add(Text(this))
}
class HTML:Element("html"){
fun head(init:Head.()->Unit){
var head = Head()
head.init()
elements.add(head)
}
fun body(init: Body.() -> Unit){
var body = Body();
body.init()
elements.add(body)
}
}
class Head:Element("head"){
fun title(init: Title.() -> Unit){
val title = Title()
title.init()
elements.add(title)
}
}
class H1:Element("h1"){
}
class P:Element("p"){
fun b(function: B.() -> Boolean) {
var b = B()
b.function()
elements.add(b)
}
fun a(href: String, init: A.() -> Unit) {
var a = A(href)
a.init();
elements.add(a)
}
}
class A(val href: String):Element("a"){
override fun render(): String = "<a href='${href}'>${elements[0].render()}</a>"
}
class B:Element("b");
class Body:Element("body"){
fun h1(function: H1.() -> Unit) {
var h1 = H1()
h1.function()
elements.add(h1)
}
fun p(function: P.() -> Unit) {
var p = P()
p.function()
elements.add(p)
}
fun a(href: String, init: A.() -> Unit) {
var a = A(href)
a.init();
elements.add(a)
}
}
class Title:Element("title");
class Text(val text:String):Element(""){
override fun render():String = text
}
fun html(init:HTML.()->Unit):HTML{
var html = HTML()
html.init()
return html
}
实现效果:
<html>
<head>
<title>
XML encoding with Kotlin
</title>
</head>
<body>
<h1>
XML encoding with Kotlin
</h1>
<p>
this format can be used as an alternative markup to XML
</p>
<a href='https://kotlinlang.org'>Kotlin</a>
<a href='https://kotlinlang.org'>Kotlin</a>
<p>
This is some
<b>
mixed
</b>
text. For more see the
project
</p>
<p>
</p>
</body>
</html>
格式化没有去处理,可能会有点丑陋哈,代码不算复杂,html
是一个高阶函数,在html
参数函数里面调用了head
和body
函数,为啥可以直接写成head
和body
呢?其实是少写了个this
,因为html
函数的参数是HTML
类的拓展函数,所以head
和body
都应该是HTML
类的函数,那样才可以直接head{}
,body{}
来调用,理清楚这点后面就很好理解.