Kotlin-19-DSL

1、定义

DSL(domain specific language),即领域专用语言:专门解决某一特定问题的计算机语言,比如JSON、XML、Anko等

2、外部DSL

  • JSON、XML、CSS、SQL、MakeFile等

上面几种语言,它们拥有自己特定的语法结构,并且不需要依赖其他任何通用开发语言,可以单独存在的。我们称为外部DSL。

比如:JSON,它可以单独作为一段单独文本,供给其他语言去使用。

3、内部DSL

  • Anko、Kolley、build.gradle等

上面几种,它们也拥有自己特定的语法结构,但是需要依赖Java或者Kotlin语言,它们才能运行的DSL语言,我们称之为内部DSL。

4、DSL优势

  • 提高开发效率

就比如我们写一段JSON格式数据文本,如果我们按照JSON语法结构的话,可以很快的书写出来,但是我们使用Java或者Kotlin等通用语言去书写相同的数据文本的话,我们需要定义很多的方法和变量。

  • 跨平台

还是用JSON举例,一段JSON格式的数据文本,我们在后台,安卓,IOS等多个平台都能直接使用,但是像Java、Kotlin这种通用语言很难做到这种跨平台性。

5、Anko的简单用例

Anko Layouts 是一套帮助我们更简洁的开发和复用 Android 布局的 DSL ,它的代码风格如下:

相比于笨重的 XML 布局方式,Anko DSL 显然是更先进和更高效的解决方案。

class MainActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
       
        super.onCreate(savedInstanceState)
        verticalLayout {
            val name = editText()
            button("Say Hello") {
                onClick { toast("Hello, ${name.text}!") }
            }
        }

    }
   
}

6、官方的输出HTML 语言的DSL语法例子

这个例子主要利用Kotlin的Lamda语法,高阶函数来书写了一个可以输出html语句的DSL语言。

import java.io.File

/**
 * This is an example of a Type-Safe Groovy-style Builder
 *
 * Builders are good for declaratively describing data in your code.
 * In this example we show how to describe an HTML page in Kotlin.
 *
 * See this page for details:
 * http://kotlinlang.org/docs/reference/type-safe-builders.html
 */

fun main(args: Array<String>) {
    val result =
        html {
            head {
                title { +"HTML encoding with Kotlin" }
            }
            body {
                h1 { +"HTML encoding with Kotlin" }
                p { +"this format can be used as an alternative markup to HTML" }

                // an element with attributes and text content
                a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }

                // mixed content
                p {
                    +"This is some"
                    b { +"mixed" }
                    +"text. For more see the"
                    a(href = "http://jetbrains.com/kotlin") { +"Kotlin" }
                    +"project"
                }
                p { +"some text" }

                // content generated from command-line arguments
                p {
                    +"Command line arguments were:"
                    ul {
                        for (arg in args)
                            li { +arg }
                    }
                }
            }
        }
    println(result)
    val a=File("a.html")
    a.writeText(result.toString())
}



interface Element {
    fun render(builder: StringBuilder, indent: String)
}

class TextElement(val text: String) : Element {
    override fun render(builder: StringBuilder, indent: String) {
        builder.append("$indent$text\n")
    }
}

abstract class Tag(val name: String) : Element {
    val children = arrayListOf<Element>()
    val attributes = hashMapOf<String, String>()

    protected fun <T : Element> initTag(tag: T, init: T.() -> Unit): T {
        tag.init()
        children.add(tag)
        return tag
    }

    override fun render(builder: StringBuilder, indent: String) {
        builder.append("$indent<$name${renderAttributes()}>\n")
        for (c in children) {
            c.render(builder, indent + "  ")
        }
        builder.append("$indent</$name>\n")
    }

    private fun renderAttributes(): String? {
        val builder = StringBuilder()
        for (a in attributes.keys) {
            builder.append(" $a=\"${attributes[a]}\"")
        }
        return builder.toString()
    }


    override fun toString(): String {
        val builder = StringBuilder()
        render(builder, "")
        return builder.toString()
    }
}

abstract class TagWithText(name: String) : Tag(name) {
    operator fun String.unaryPlus() {
        children.add(TextElement(this))
    }
}

class HTML() : TagWithText("html") {
    fun head(init: Head.() -> Unit) = initTag(Head(), init)

    fun body(init: Body.() -> Unit) = initTag(Body(), init)
}

class Head() : TagWithText("head") {
    fun title(init: Title.() -> Unit) = initTag(Title(), init)
}

class Title() : TagWithText("title")

abstract class BodyTag(name: String) : TagWithText(name) {
    fun b(init: B.() -> Unit) = initTag(B(), init)
    fun p(init: P.() -> Unit) = initTag(P(), init)
    fun h1(init: H1.() -> Unit) = initTag(H1(), init)
    fun ul(init: UL.() -> Unit) = initTag(UL(), init)
    fun a(href: String, init: A.() -> Unit) {
        val a = initTag(A(), init)
        a.href = href
    }
}

class Body() : BodyTag("body")
class UL() : BodyTag("ul") {
    fun li(init: LI.() -> Unit) = initTag(LI(), init)
}

class B() : BodyTag("b")
class LI() : BodyTag("li")
class P() : BodyTag("p")
class H1() : BodyTag("h1")

class A() : BodyTag("a") {
    public var href: String
        get() = attributes["href"]!!
        set(value) {
            attributes["href"] = value
        }
}

fun html(init: HTML.() -> Unit): HTML {
    val html = HTML()
    html.init()
    return html
}

它的输出结果:

<html>
  <head>
    <title>
      HTML encoding with Kotlin
    </title>
  </head>
  <body>
    <h1>
      HTML encoding with Kotlin
    </h1>
    <p>
      this format can be used as an alternative markup to HTML
    </p>
    <a href="http://jetbrains.com/kotlin">
      Kotlin
    </a>
    <p>
      This is some
      <b>
        mixed
      </b>
      text. For more see the
      <a href="http://jetbrains.com/kotlin">
        Kotlin
      </a>
      project
    </p>
    <p>
      some text
    </p>
    <p>
      Command line arguments were:
      <ul>
      </ul>
    </p>
  </body>
</html>

发布了82 篇原创文章 · 获赞 16 · 访问量 26万+

猜你喜欢

转载自blog.csdn.net/qq_34589749/article/details/103653718
DSL
今日推荐