专栏首页一个会写诗的程序员的博客《Kotlin 程序设计》第十一章 Kotlin实现DSL

《Kotlin 程序设计》第十一章 Kotlin实现DSL

第十一章 Kotlin实现DSL

正式上架:《Kotlin极简教程》Official on shelves: Kotlin Programming minimalist tutorial 京东JD:https://item.jd.com/12181725.html 天猫Tmall:https://detail.tmall.com/item.htm?id=558540170670

DSL

DSL 即 domain-specific languages,领域特定语言。和一般的编程语言不同,领域特定语言只能用于特定的领域中并且表现形式有限。领域特定语言最大的功能就是可以让语言本身更容易阅读,方便开发者和领域专家进行交流。

实现 DSL

Java 中 DSL 的最简单实现方式就是构造器模式,而在 Kotlin 过去的版本中可以省略 .,所以可以写成更易读的代码,但是现在的版本已经不支持了。

构造器模式

Machine machine = new Machine.Builder() .setCore(8) .setArch("64 bits") .setOs("Linux") .build(); DSL 方式

定义必要的类和方法

data class Cpu(val core: Int, val arch: String)

class Machine { var cpu: Cpu? = null var os: String? = null

fun having(cores: Int, arch: String): Machine {
    cpu = Cpu(cores, arch)
    return this
}

fun os(os: String): Machine {
    this.os = os
    return this
}

override fun toString(): String {
    return "Machine{cpu=$cpu, os='$os'"
}

} 构建对象

val m1 = Machine().having(8, "64 bits").os("linux") val m2 = Machine().having(4, "32 bits").os("Windows") 可以看到使用 DSL 后代码更加易读。

使用闭包构建 DSL

Kotlin 像 Groovy 一样也能通过闭包构建 DSL,语法看起来很像 Groovy。

定义必要的类和方法

class EmailSpec { fun from(from: String) = println("From: $from") fun to(to: String) = println("To: $to") fun subject(subject: String) = println("Subject: $subject") fun body(init: BodySpec.() -> Unit): BodySpec { val body = BodySpec() body.init() return body } }

class BodySpec { fun p(p: String) = println("P: $p") }

fun email(init: EmailSpec.() -> Unit): EmailSpec { val email = EmailSpec() email.init() return email } 调用 DSL 语句

email { from ("dsl-guru@mycompany.com") to ("john.doe@waitaminute.com") subject ("The pope has resigned!") body { p ("Really, the pope has resigned!") } }

val data = mapOf(1 to "one", 2 to "two")

createHTML().table {
    //遍历数据
    for ((num, string) in data) {
        //创建 HTML 标签的函数
        tr {
           td { +"$num" } 
           td { +string }
        }
    }
}
/**
 * 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
 */
package html

fun main(args: Array<String>) {
    val 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 = "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)
}

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
}

https://www.kotliner.cn/2017/05/15/2017-5-11-KotlinDSL2/

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • 《Kotin 极简教程》第7章 面向对象编程(OOP)(1)第7章 面向对象编程(OOP)《Kotlin极简教程》正式上架:

    在前面的章节中,我们学习了Kotlin的语言基础知识、类型系统、集合类以及泛型相关的知识。在本章节以及下一章中,我们将一起来学习Kotlin对面向对象编程以及函...

    一个会写诗的程序员
  • 《Kotlin极简教程》第3章 Kotlin语言基础第3章 Kotlin语言基础《Kotlin极简教程》正式上架:参考资料

    学习任何东西,都是一个由表及里的过程。学习一门编程语言也一样。对于一门编程语言来说,“表” 就是基本词汇(关键字、标识符等)、句子(表达式)和语法。

    一个会写诗的程序员
  • 《Kotin 编程思想·实战》

    Xtend是Eclipse推出的一个新的JVM语言,并无意替代Java,而是以己之长补Java之短,精简代码,无类型,改进可读和维护。Eclipse Xtend...

    一个会写诗的程序员
  • Scala 操作 HBase2.0 数据库

    ZHANGHAO
  • Scala日期操作

    董可伦
  • 大数据技术之_27_电商平台数据分析项目_03_项目概述 + 项目主体架构 + 模拟业务数据源 + 程序框架解析 + 需求解析 + 项目总结

    1、user_visit_action user_visit_action 表,存放网站或者 APP 每天的点击流数据。通俗地讲,就是用户对 网站/APP 每点...

    黑泽君
  • [剑指offer] 序列化二叉树

    原文地址: https://weiweiblog.cn/serialize/

    尾尾部落
  • 张嘴伸手,闭嘴收手,东大和庆大联合开发FaceDrive,超级机械臂只用表情就能控制

    或许不少人会选择章鱼博士,作为蜘蛛侠的死对头,拥有四只机械臂的章鱼博士从各种意义上说都十分“难缠”,当然,作为反派,他也足够让观众留下深刻的印象。

    大数据文摘
  • Scala教程之:Scala基础

    这篇文章我们大概过一下Scala的基础概念,后面的文章我们会有更详细的讲解Scala的具体内容。

    程序那些事
  • 通过定义UnityContainer扩展变”Explicit Interception”为”Automatic Interception”

    Unity是微软P&P部门开发的一个轻量级IoC框架,通过Interception机制可以实现基于三种拦截机制的AOP。不过Unity仅仅提供“显式”拦截机制,...

    蒋金楠

扫码关注云+社区

领取腾讯云代金券