如何在Kotlin DSL定义中优雅地结合父母和孩子的标签

使用Kotlin我想定义一个DSL来初始化一个结构。 正如你所看到的,我想创建一个模块,每个模块都有多个字段。

class DSL : ModuleDSL() { init { module(Module("myModule")) { field("Test", "Test") field("Test", "Test") field("Test", "Test") } module(Module("myOtherModule")) { field("Test", "Test") field("Test", "Test") field("Test", "Test") } } } 

每个字段必须连接到模块。 Whit在包含字段定义的闭包中,afaik我没有对模块的引用。 什么是创建模块和它的领域之间的连接最优雅的方式。

为了完整起见,这些是其余的课程

 open class ModuleDSL { fun field(fieldname: String, attributename: String) { println("${fieldname} is named ${attributename}") } fun module(module: Module, function: () -> Unit) { function.invoke() } fun createModel() { println("Create my model") } } class Module(name: String) { init { println("Create entity ${name}") } } fun main(args: Array<String>) { val myModuleDsl = DSL() myModuleDsl.createModel() } 

经过一番尝试,我找到了一个合理的优雅的解决方案,从互联网上的一个例子中提取。

配置在配置类中。 加上有趣的主要看起来像这样:

 class MyModuleConfigurator : ModuleConfigurator() { fun bld() = module("MyModule1") { +"Text" field { +"Fieldtext 1" } field { +"Fieldtext 2a" +"Fieldtext 2b" form("form in field 2") } form("Form 1") } } fun main(args: Array<String>) { val myHTML = MyModuleConfigurator() myHTML.bld() } 

配置类是从实现配置标签的主类派生的。 看到一些额外的信息的意见:

 open class ModuleConfigurator { // Triggers on 'module' keyword protected fun module(name: String, init: Module.() -> Unit) { val module = Module(name) module.init() // Add your post DSL processing operation here println(module.toString()) } class Module(val name: String) { // Triggers on 'field' keyword in the 'module' fun field(init: Field.() -> Unit) = initTag(this, init) // Triggers on 'form' keyword fun form(name: String) { println("form with name ${name} in module ${this.name}") } // Triggers on + keyword operator fun String.unaryPlus() { val textElement = ModuleConfigurator.TextElement(this) println("Module unary plus (name = ${textElement})") } // Other module internals private fun initTag(module: Module, init: Field.() -> Unit) { val myField = Field(module) module.add(myField) myField.init() } private fun add(myField: Field) { // Hook to add field to module } override fun toString(): String { return "Module(${name})" } } // Helper to unwrap the string in the Unary Plus class TextElement(val text: String) { override fun toString(): String { return "$text" } } class Field(val module: ModuleConfigurator.Module) { operator fun String.unaryPlus() { val textElement = ModuleConfigurator.TextElement(this) println("Field unary plus in module ${module.toString()}, text = '${textElement}'") } } } 

请享用!