3-2-1 DSL-真实案例

20 阅读5分钟

Kotlin自定义DSL真实案例

下面我将通过几个完整的真实案例来展示Kotlin自定义DSL的实践应用。

案例1:HTTP API客户端DSL

目标:创建声明式的HTTP请求构建器

// ================ HTTP DSL 核心 ================

/**
 * HTTP方法枚举
 */
enum class HttpMethod {
    GET, POST, PUT, DELETE, PATCH, HEAD, OPTIONS
}

/**
 * HTTP客户端配置
 */
data class HttpClientConfig(
    var baseUrl: String = "",
    var connectTimeout: Long = 10_000,
    var readTimeout: Long = 10_000,
    var writeTimeout: Long = 10_000,
    var headers: MutableMap<String, String> = mutableMapOf(
        "Content-Type" to "application/json"
    )
)

/**
 * HTTP请求构建器
 */
class HttpRequestBuilder internal constructor() {
    var method: HttpMethod = HttpMethod.GET
    var path: String = ""
    val headers: MutableMap<String, String> = mutableMapOf()
    val queryParams: MutableMap<String, Any> = mutableMapOf()
    var body: Any? = null
    
    fun header(name: String, value: String) {
        headers[name] = value
    }
    
    fun queryParam(name: String, value: Any) {
        queryParams[name] = value
    }
    
    fun jsonBody(init: JsonBodyBuilder.() -> Unit) {
        body = JsonBodyBuilder().apply(init).build()
    }
    
    fun formBody(init: FormBodyBuilder.() -> Unit) {
        body = FormBodyBuilder().apply(init).build()
    }
    
    internal fun build(): HttpRequest {
        return HttpRequest(method, path, headers, queryParams, body)
    }
}

/**
 * JSON请求体构建器
 */
class JsonBodyBuilder {
    private val properties = mutableMapOf<String, Any?>()
    
    operator fun String.invoke(value: Any?) {
        properties[this] = value
    }
    
    fun property(name: String, value: Any?) {
        properties[name] = value
    }
    
    fun array(name: String, init: JsonArrayBuilder.() -> Unit) {
        properties[name] = JsonArrayBuilder().apply(init).build()
    }
    
    fun obj(name: String, init: JsonBodyBuilder.() -> Unit) {
        properties[name] = JsonBodyBuilder().apply(init).build()
    }
    
    internal fun build(): Map<String, Any?> = properties
}

/**
 * JSON数组构建器
 */
class JsonArrayBuilder {
    private val items = mutableListOf<Any?>()
    
    fun add(value: Any?) {
        items.add(value)
    }
    
    fun addObj(init: JsonBodyBuilder.() -> Unit) {
        items.add(JsonBodyBuilder().apply(init).build())
    }
    
    fun addArray(init: JsonArrayBuilder.() -> Unit) {
        items.add(JsonArrayBuilder().apply(init).build())
    }
    
    internal fun build(): List<Any?> = items
}

/**
 * 表单请求体构建器
 */
class FormBodyBuilder {
    private val params = mutableMapOf<String, Any>()
    
    operator fun String.invoke(value: Any) {
        params[this] = value
    }
    
    fun param(name: String, value: Any) {
        params[name] = value
    }
    
    internal fun build(): Map<String, Any> = params
}

/**
 * HTTP请求数据类
 */
data class HttpRequest(
    val method: HttpMethod,
    val path: String,
    val headers: Map<String, String>,
    val queryParams: Map<String, Any>,
    val body: Any?
)

/**
 * HTTP响应数据类
 */
data class HttpResponse<T>(
    val statusCode: Int,
    val body: T?,
    val headers: Map<String, String>
)

/**
 * HTTP客户端
 */
class HttpClient(private val config: HttpClientConfig) {
    
    suspend inline fun <reified T> request(
        init: HttpRequestBuilder.() -> Unit
    ): HttpResponse<T> {
        val requestBuilder = HttpRequestBuilder().apply(init)
        
        // 合并全局配置和请求特定的headers
        val allHeaders = config.headers.toMutableMap()
        allHeaders.putAll(requestBuilder.headers)
        
        // 构建完整URL
        val url = buildUrl(requestBuilder)
        
        // 在实际项目中,这里会使用Ktor、OkHttp等HTTP客户端
        println("发送HTTP请求:")
        println("  URL: $url")
        println("  方法: ${requestBuilder.method}")
        println("  Headers: $allHeaders")
        println("  Query参数: ${requestBuilder.queryParams}")
        println("  Body: ${requestBuilder.body}")
        
        // 模拟响应
        return HttpResponse(
            statusCode = 200,
            body = null,
            headers = mapOf("Content-Type" to "application/json")
        )
    }
    
    private fun buildUrl(requestBuilder: HttpRequestBuilder): String {
        val base = if (config.baseUrl.endsWith("/")) 
            config.baseUrl.dropLast(1) else config.baseUrl
        val path = if (requestBuilder.path.startsWith("/")) 
            requestBuilder.path else "/${requestBuilder.path}"
        
        val queryString = if (requestBuilder.queryParams.isNotEmpty()) {
            "?" + requestBuilder.queryParams.entries
                .joinToString("&") { "${it.key}=${it.value}" }
        } else ""
        
        return "$base$path$queryString"
    }
}

/**
 * HTTP DSL入口函数
 */
fun httpClient(init: HttpClientConfig.() -> Unit): HttpClient {
    val config = HttpClientConfig().apply(init)
    return HttpClient(config)
}

// ================ 使用示例 ================

// 示例1:简单的GET请求
fun example1() {
    val client = httpClient {
        baseUrl = "https://api.example.com"
        headers["User-Agent"] = "MyApp/1.0"
    }
    
    // 在协程中执行
    /* 
    runBlocking {
        val response = client.request<String> {
            method = HttpMethod.GET
            path = "/users"
            queryParam("page", 1)
            queryParam("limit", 20)
            header("Authorization", "Bearer token123")
        }
    }
    */
}

// 示例2:复杂的POST请求
fun example2() {
    val client = httpClient {
        baseUrl = "https://api.example.com"
        connectTimeout = 15000
        readTimeout = 30000
    }
    
    // 创建嵌套JSON请求
    /* 
    runBlocking {
        val response = client.request<Map<String, Any>> {
            method = HttpMethod.POST
            path = "/orders"
            
            jsonBody {
                "orderId"("12345")
                "customer" {
                    "name"("张三")
                    "email"("zhangsan@example.com")
                    "phone"("13800138000")
                }
                "items" array {
                    addObj {
                        "productId"("P001")
                        "quantity"(2)
                        "price"(99.99)
                    }
                    addObj {
                        "productId"("P002")
                        "quantity"(1)
                        "price"(199.99)
                    }
                }
                "shippingAddress" {
                    "city"("北京")
                    "district"("朝阳区")
                    "street"("建国门外大街")
                }
            }
        }
    }
    */
}

// 示例3:表单提交
fun example3() {
    val client = httpClient {
        baseUrl = "https://auth.example.com"
    }
    
    /* 
    runBlocking {
        val response = client.request<String> {
            method = HttpMethod.POST
            path = "/login"
            
            formBody {
                "username"("zhangsan")
                "password"("secret123")
                "grant_type"("password")
            }
            
            header("Content-Type", "application/x-www-form-urlencoded")
        }
    }
    */
}

案例2:数据库查询DSL

目标:创建类型安全的SQL查询构建器

// ================ SQL DSL 核心 ================

/**
 * SQL操作符
 */
sealed class SqlOperator(val symbol: String) {
    object Equals : SqlOperator("=")
    object NotEquals : SqlOperator("!=")
    object GreaterThan : SqlOperator(">")
    object GreaterThanOrEquals : SqlOperator(">=")
    object LessThan : SqlOperator("<")
    object LessThanOrEquals : SqlOperator("<=")
    object Like : SqlOperator("LIKE")
    object In : SqlOperator("IN")
    object NotIn : SqlOperator("NOT IN")
    object IsNull : SqlOperator("IS NULL")
    object IsNotNull : SqlOperator("IS NOT NULL")
}

/**
 * SQL连接条件
 */
sealed class SqlJoinType {
    object Inner : SqlJoinType()
    object Left : SqlJoinType()
    object Right : SqlJoinType()
    object Full : SqlJoinType()
}

/**
 * 查询条件构建器
 */
class WhereClauseBuilder {
    private val conditions = mutableListOf<String>()
    private val parameters = mutableMapOf<String, Any>()
    
    fun and(condition: String, paramName: String? = null, value: Any? = null) {
        conditions.add("AND $condition")
        paramName?.let { parameters[it] = value!! }
    }
    
    fun or(condition: String, paramName: String? = null, value: Any? = null) {
        conditions.add("OR $condition")
        paramName?.let { parameters[it] = value!! }
    }
    
    fun eq(column: String, value: Any) {
        val paramName = "p${parameters.size}"
        conditions.add("AND $column = :$paramName")
        parameters[paramName] = value
    }
    
    fun ne(column: String, value: Any) {
        val paramName = "p${parameters.size}"
        conditions.add("AND $column != :$paramName")
        parameters[paramName] = value
    }
    
    fun gt(column: String, value: Any) {
        val paramName = "p${parameters.size}"
        conditions.add("AND $column > :$paramName")
        parameters[paramName] = value
    }
    
    fun `in`(column: String, values: List<Any>) {
        val paramNames = values.mapIndexed { index, _ -> 
            "p${parameters.size + index}"
        }
        conditions.add("AND $column IN (${paramNames.joinToString { ":$it" }})")
        paramNames.forEachIndexed { index, name -> 
            parameters[name] = values[index]
        }
    }
    
    fun like(column: String, pattern: String) {
        val paramName = "p${parameters.size}"
        conditions.add("AND $column LIKE :$paramName")
        parameters[paramName] = pattern
    }
    
    fun isNull(column: String) {
        conditions.add("AND $column IS NULL")
    }
    
    fun isNotNull(column: String) {
        conditions.add("AND $column IS NOT NULL")
    }
    
    internal fun build(): Pair<String, Map<String, Any>> {
        val whereClause = if (conditions.isEmpty()) {
            ""
        } else {
            "WHERE " + conditions.joinToString(" ")
                .removePrefix("AND ")
                .removePrefix("OR ")
        }
        return whereClause to parameters
    }
}

/**
 * 排序方向
 */
enum class SortDirection {
    ASC, DESC
}

/**
 * 查询构建器
 */
class SelectQueryBuilder<T : Any> {
    private var distinct: Boolean = false
    private val columns = mutableListOf<String>()
    private val tables = mutableListOf<String>()
    private val joins = mutableListOf<String>()
    private val whereBuilder = WhereClauseBuilder()
    private val groupByColumns = mutableListOf<String>()
    private val havingBuilder = WhereClauseBuilder()
    private val orderByColumns = mutableListOf<String>()
    private var limitCount: Int? = null
    private var offsetCount: Int? = null
    
    fun distinct() {
        distinct = true
    }
    
    fun select(vararg cols: String) {
        columns.addAll(cols)
    }
    
    fun from(table: String) {
        tables.add(table)
    }
    
    fun join(
        type: SqlJoinType = SqlJoinType.Inner,
        table: String,
        on: String
    ) {
        val joinType = when (type) {
            SqlJoinType.Inner -> "INNER JOIN"
            SqlJoinType.Left -> "LEFT JOIN"
            SqlJoinType.Right -> "RIGHT JOIN"
            SqlJoinType.Full -> "FULL JOIN"
        }
        joins.add("$joinType $table ON $on")
    }
    
    fun where(init: WhereClauseBuilder.() -> Unit) {
        whereBuilder.init()
    }
    
    fun groupBy(vararg columns: String) {
        groupByColumns.addAll(columns)
    }
    
    fun having(init: WhereClauseBuilder.() -> Unit) {
        havingBuilder.init()
    }
    
    fun orderBy(column: String, direction: SortDirection = SortDirection.ASC) {
        orderByColumns.add("$column $direction")
    }
    
    fun limit(count: Int) {
        limitCount = count
    }
    
    fun offset(count: Int) {
        offsetCount = count
    }
    
    internal fun build(): Pair<String, Map<String, Any>> {
        val selectClause = if (distinct) "SELECT DISTINCT" else "SELECT"
        val columnsClause = if (columns.isEmpty()) "*" else columns.joinToString(", ")
        val fromClause = "FROM ${tables.joinToString(", ")}"
        val joinClause = if (joins.isNotEmpty()) joins.joinToString(" ") else ""
        
        val (whereClause, whereParams) = whereBuilder.build()
        val (havingClause, havingParams) = havingBuilder.build()
        
        val groupByClause = if (groupByColumns.isNotEmpty()) {
            "GROUP BY ${groupByColumns.joinToString(", ")}"
        } else ""
        
        val orderByClause = if (orderByColumns.isNotEmpty()) {
            "ORDER BY ${orderByColumns.joinToString(", ")}"
        } else ""
        
        val limitClause = limitCount?.let { "LIMIT $it" } ?: ""
        val offsetClause = offsetCount?.let { "OFFSET $it" } ?: ""
        
        val sql = listOf(
            selectClause, columnsClause,
            fromClause, joinClause,
            whereClause, groupByClause,
            havingClause, orderByClause,
            limitClause, offsetClause
        ).filter { it.isNotBlank() }.joinToString(" ")
        
        val allParams = mutableMapOf<String, Any>()
        allParams.putAll(whereParams)
        allParams.putAll(havingParams)
        
        return sql to allParams
    }
}

/**
 * 插入构建器
 */
class InsertQueryBuilder {
    private var table: String = ""
    private val columns = mutableListOf<String>()
    private val values = mutableMapOf<String, Any>()
    
    fun into(table: String) {
        this.table = table
    }
    
    operator fun String.invoke(value: Any) {
        columns.add(this)
        values[this] = value
    }
    
    fun column(name: String, value: Any) {
        columns.add(name)
        values[name] = value
    }
    
    internal fun build(): Pair<String, Map<String, Any>> {
        val columnsClause = columns.joinToString(", ", "(", ")")
        val paramNames = columns.mapIndexed { index, _ -> "p$index" }
        val valuesClause = paramNames.joinToString(", ", "VALUES (", ")")
        
        val sql = "INSERT INTO $table $columnsClause $valuesClause"
        
        val params = paramNames.mapIndexed { index, paramName ->
            paramName to values[columns[index]]!!
        }.toMap()
        
        return sql to params
    }
}

/**
 * 更新构建器
 */
class UpdateQueryBuilder {
    private var table: String = ""
    private val sets = mutableMapOf<String, Any>()
    private val whereBuilder = WhereClauseBuilder()
    
    fun table(table: String) {
        this.table = table
    }
    
    fun set(column: String, value: Any) {
        sets[column] = value
    }
    
    fun where(init: WhereClauseBuilder.() -> Unit) {
        whereBuilder.init()
    }
    
    internal fun build(): Pair<String, Map<String, Any>> {
        val setClause = sets.entries.mapIndexed { index, (column, _) ->
            "$column = :set$index"
        }.joinToString(", ")
        
        val (whereClause, whereParams) = whereBuilder.build()
        
        val sql = "UPDATE $table SET $setClause $whereClause"
        
        val params = mutableMapOf<String, Any>()
        sets.entries.forEachIndexed { index, (_, value) ->
            params["set$index"] = value
        }
        params.putAll(whereParams)
        
        return sql to params
    }
}

/**
 * 数据库DSL入口
 */
object DatabaseDSL {
    
    fun <T : Any> select(init: SelectQueryBuilder<T>.() -> Unit): Pair<String, Map<String, Any>> {
        return SelectQueryBuilder<T>().apply(init).build()
    }
    
    fun insert(init: InsertQueryBuilder.() -> Unit): Pair<String, Map<String, Any>> {
        return InsertQueryBuilder().apply(init).build()
    }
    
    fun update(init: UpdateQueryBuilder.() -> Unit): Pair<String, Map<String, Any>> {
        return UpdateQueryBuilder().apply(init).build()
    }
    
    fun deleteFrom(table: String): String {
        return "DELETE FROM $table"
    }
}

// ================ 使用示例 ================

// 示例1:复杂查询
fun buildComplexQuery() {
    val (sql, params) = DatabaseDSL.select<User> {
        distinct()
        select("id", "name", "email", "created_at")
        from("users")
        join(SqlJoinType.Left, "orders", "users.id = orders.user_id")
        
        where {
            eq("status", "ACTIVE")
            gt("age", 18)
            `in`("city", listOf("北京", "上海", "广州"))
            like("name", "%张%")
        }
        
        groupBy("users.id")
        
        having {
            gt("COUNT(orders.id)", 5)
        }
        
        orderBy("created_at", SortDirection.DESC)
        limit(20)
        offset(0)
    }
    
    println("SQL: $sql")
    println("参数: $params")
}

// 示例2:插入数据
fun buildInsertQuery() {
    val (sql, params) = DatabaseDSL.insert {
        into("users")
        "name"("张三")
        "email"("zhangsan@example.com")
        "age"(25)
        "city"("北京")
        "created_at"(System.currentTimeMillis())
    }
    
    println("SQL: $sql")
    println("参数: $params")
}

// 示例3:更新数据
fun buildUpdateQuery() {
    val (sql, params) = DatabaseDSL.update {
        table("users")
        set("email", "newemail@example.com")
        set("age", 26)
        
        where {
            eq("id", 123)
        }
    }
    
    println("SQL: $sql")
    println("参数: $params")
}

// 实体类示例
data class User(
    val id: Int,
    val name: String,
    val email: String,
    val age: Int,
    val city: String,
    val createdAt: Long
)

案例3:配置管理DSL

目标:创建类型安全的应用程序配置构建器

// ================ 配置管理DSL ================

/**
 * 配置值密封类
 */
sealed class ConfigValue {
    data class StringValue(val value: String) : ConfigValue()
    data class IntValue(val value: Int) : ConfigValue()
    data class BooleanValue(val value: Boolean) : ConfigValue()
    data class DoubleValue(val value: Double) : ConfigValue()
    data class ListValue(val values: List<ConfigValue>) : ConfigValue()
    data class MapValue(val map: Map<String, ConfigValue>) : ConfigValue()
    
    fun asString(): String = when (this) {
        is StringValue -> value
        else -> throw IllegalStateException("不是字符串类型")
    }
    
    fun asInt(): Int = when (this) {
        is IntValue -> value
        else -> throw IllegalStateException("不是整数类型")
    }
    
    fun asBoolean(): Boolean = when (this) {
        is BooleanValue -> value
        else -> throw IllegalStateException("不是布尔类型")
    }
    
    fun asDouble(): Double = when (this) {
        is DoubleValue -> value
        else -> throw IllegalStateException("不是浮点数类型")
    }
    
    fun asList(): List<ConfigValue> = when (this) {
        is ListValue -> values
        else -> throw IllegalStateException("不是列表类型")
    }
    
    fun asMap(): Map<String, ConfigValue> = when (this) {
        is MapValue -> map
        else -> throw IllegalStateException("不是映射类型")
    }
}

/**
 * 配置构建器
 */
class ConfigBuilder {
    private val config = mutableMapOf<String, ConfigValue>()
    
    operator fun String.invoke(value: String) {
        config[this] = ConfigValue.StringValue(value)
    }
    
    operator fun String.invoke(value: Int) {
        config[this] = ConfigValue.IntValue(value)
    }
    
    operator fun String.invoke(value: Boolean) {
        config[this] = ConfigValue.BooleanValue(value)
    }
    
    operator fun String.invoke(value: Double) {
        config[this] = ConfigValue.DoubleValue(value)
    }
    
    operator fun String.invoke(vararg values: ConfigValue) {
        config[this] = ConfigValue.ListValue(values.toList())
    }
    
    fun list(name: String, init: ListBuilder.() -> Unit) {
        config[name] = ConfigValue.ListValue(ListBuilder().apply(init).build())
    }
    
    fun map(name: String, init: ConfigBuilder.() -> Unit) {
        config[name] = ConfigValue.MapValue(ConfigBuilder().apply(init).build())
    }
    
    fun env(name: String, defaultValue: String? = null) {
        val envValue = System.getenv(name) ?: defaultValue
        envValue?.let {
            config[name] = ConfigValue.StringValue(it)
        }
    }
    
    fun prop(name: String, defaultValue: String? = null) {
        val propValue = System.getProperty(name) ?: defaultValue
        propValue?.let {
            config[name] = ConfigValue.StringValue(it)
        }
    }
    
    internal fun build(): Map<String, ConfigValue> = config
}

/**
 * 列表构建器
 */
class ListBuilder {
    private val list = mutableListOf<ConfigValue>()
    
    fun add(value: String) {
        list.add(ConfigValue.StringValue(value))
    }
    
    fun add(value: Int) {
        list.add(ConfigValue.IntValue(value))
    }
    
    fun add(value: Boolean) {
        list.add(ConfigValue.BooleanValue(value))
    }
    
    fun add(value: Double) {
        list.add(ConfigValue.DoubleValue(value))
    }
    
    fun addList(init: ListBuilder.() -> Unit) {
        list.add(ConfigValue.ListValue(ListBuilder().apply(init).build()))
    }
    
    fun addMap(init: ConfigBuilder.() -> Unit) {
        list.add(ConfigValue.MapValue(ConfigBuilder().apply(init).build()))
    }
    
    internal fun build(): List<ConfigValue> = list
}

/**
 * 配置文件类
 */
class Config(private val config: Map<String, ConfigValue>) {
    
    fun getString(key: String): String? {
        return config[key]?.asString()
    }
    
    fun getInt(key: String): Int? {
        return config[key]?.asInt()
    }
    
    fun getBoolean(key: String): Boolean? {
        return config[key]?.asBoolean()
    }
    
    fun getDouble(key: String): Double? {
        return config[key]?.asDouble()
    }
    
    fun getList(key: String): List<ConfigValue>? {
        return config[key]?.asList()
    }
    
    fun getMap(key: String): Map<String, ConfigValue>? {
        return config[key]?.asMap()
    }
    
    fun getSubConfig(key: String): Config? {
        return getMap(key)?.let { Config(it) }
    }
    
    fun requireString(key: String): String {
        return getString(key) ?: throw IllegalArgumentException("配置项 $key 不存在或不是字符串类型")
    }
    
    fun requireInt(key: String): Int {
        return getInt(key) ?: throw IllegalArgumentException("配置项 $key 不存在或不是整数类型")
    }
    
    override fun toString(): String {
        return formatMap(config, 0)
    }
    
    private fun formatMap(map: Map<String, ConfigValue>, indent: Int): String {
        val indentStr = "  ".repeat(indent)
        return map.entries.joinToString("\n") { (key, value) ->
            "$indentStr$key: ${formatValue(value, indent + 1)}"
        }
    }
    
    private fun formatValue(value: ConfigValue, indent: Int): String = when (value) {
        is ConfigValue.StringValue -> "\"${value.value}\""
        is ConfigValue.IntValue -> value.value.toString()
        is ConfigValue.BooleanValue -> value.value.toString()
        is ConfigValue.DoubleValue -> value.value.toString()
        is ConfigValue.ListValue -> formatList(value.values, indent)
        is ConfigValue.MapValue -> "{\n${formatMap(value.map, indent)}\n${"  ".repeat(indent - 1)}}"
    }
    
    private fun formatList(list: List<ConfigValue>, indent: Int): String {
        val indentStr = "  ".repeat(indent)
        return list.joinToString(
            prefix = "[\n",
            separator = ",\n",
            postfix = "\n${"  ".repeat(indent - 1)}]"
        ) { value ->
            "$indentStr${formatValue(value, indent + 1)}"
        }
    }
}

/**
 * 配置DSL入口
 */
fun config(init: ConfigBuilder.() -> Unit): Config {
    val configMap = ConfigBuilder().apply(init).build()
    return Config(configMap)
}

// ================ 使用示例 ================

// 示例:构建完整的应用配置
fun buildApplicationConfig() {
    val appConfig = config {
        // 基础配置
        "app.name"("订单管理系统")
        "app.version"("1.0.0")
        "app.debug"(false)
        
        // 服务器配置
        map("server") {
            "host"("0.0.0.0")
            "port"(8080)
            "contextPath"("/api")
            "maxThreads"(200)
            "idleTimeout"(30000)
        }
        
        // 数据库配置
        map("database") {
            map("primary") {
                "driver"("org.postgresql.Driver")
                "url"("jdbc:postgresql://localhost:5432/order_db")
                "username"("admin")
                // 从环境变量读取密码
                env("DB_PASSWORD")
                "poolSize"(20)
                "connectionTimeout"(5000)
            }
            
            map("replica") {
                "driver"("org.postgresql.Driver")
                "url"("jdbc:postgresql://replica:5432/order_db")
                "username"("readonly")
                env("DB_REPLICA_PASSWORD", "default_pass")
                "poolSize"(10)
            }
        }
        
        // Redis配置
        map("redis") {
            map("cluster") {
                list("nodes") {
                    add("redis1:6379")
                    add("redis2:6379")
                    add("redis3:6379")
                }
                "password"("redis_pass_123")
                "timeout"(2000)
                "maxTotal"(100)
                "maxIdle"(20)
            }
        }
        
        // 缓存配置
        map("cache") {
            map("user") {
                "enabled"(true)
                "ttl"(3600000) // 1小时
                "maxSize"(10000)
            }
            map("product") {
                "enabled"(true)
                "ttl"(1800000) // 30分钟
                "maxSize"(50000)
            }
        }
        
        // 消息队列配置
        map("mq") {
            "type"("kafka")
            map("kafka") {
                "bootstrapServers"("kafka1:9092,kafka2:9092")
                "acks"("all")
                "retries"(3)
                list("topics") {
                    add("order.created")
                    add("order.updated")
                    add("payment.processed")
                }
            }
        }
        
        // 外部服务配置
        map("externalServices") {
            map("paymentGateway") {
                "baseUrl"("https://api.payment.com/v1")
                "apiKey"("pk_test_123456")
                "timeout"(10000)
                "retryAttempts"(3)
            }
            
            map("smsService") {
                "provider"("阿里云")
                "accessKey"("your_access_key")
                env("SMS_SECRET")
                "signName"("订单系统")
            }
        }
        
        // 业务配置
        map("business") {
            map("order") {
                "autoCancelMinutes"(30)
                "maxItemsPerOrder"(50)
                "allowPartialShipment"(true)
            }
            
            map("inventory") {
                "lowStockThreshold"(10)
                "reservationTimeout"(300000) // 5分钟
            }
            
            map("delivery") {
                list("supportedRegions") {
                    add("北京")
                    add("上海")
                    add("广州")
                    add("深圳")
                }
                "expressFee"(15.0)
                "freeShippingThreshold"(199.0)
            }
        }
        
        // 监控配置
        map("monitoring") {
            "enabled"(true)
            "metricsPrefix"("order.system")
            map("prometheus") {
                "port"(9095)
                "path"("/metrics")
            }
            
            map("logging") {
                "level"("INFO")
                "filePath"("/var/log/order-system.log")
                "maxSize"(104857600) // 100MB
                "maxBackups"(10)
            }
        }
    }
    
    // 使用配置
    println("应用配置:")
    println(appConfig)
    
    // 访问具体配置
    val serverHost = appConfig.getSubConfig("server")?.getString("host")
    val dbUrl = appConfig.getSubConfig("database")?.getSubConfig("primary")?.getString("url")
    val redisNodes = appConfig.getSubConfig("redis")?.getSubConfig("cluster")?.getList("nodes")
    
    println("\n关键配置:")
    println("服务器主机: $serverHost")
    println("数据库URL: $dbUrl")
    println("Redis节点: $redisNodes")
}

// ================ 配置验证器 ================

/**
 * 配置验证器DSL
 */
class ConfigValidator(private val config: Config) {
    
    fun validate(init: ValidationBuilder.() -> Unit): ValidationResult {
        return ValidationBuilder(config).apply(init).validate()
    }
}

class ValidationBuilder(private val config: Config) {
    private val errors = mutableListOf<String>()
    
    fun require(key: String) {
        if (config.getString(key) == null) {
            errors.add("缺少必需的配置项: $key")
        }
    }
    
    fun requireInRange(key: String, min: Int, max: Int) {
        val value = config.getInt(key)
        when {
            value == null -> errors.add("配置项 $key 不存在")
            value < min || value > max -> errors.add("配置项 $key 的值 $value 不在范围 [$min, $max] 内")
        }
    }
    
    fun requireNotEmpty(key: String) {
        val value = config.getString(key)
        if (value.isNullOrEmpty()) {
            errors.add("配置项 $key 不能为空")
        }
    }
    
    fun requireMatch(key: String, regex: Regex) {
        val value = config.getString(key)
        if (value != null && !regex.matches(value)) {
            errors.add("配置项 $key 的值 '$value' 不符合格式要求")
        }
    }
    
    internal fun validate(): ValidationResult {
        return ValidationResult(errors)
    }
}

data class ValidationResult(val errors: List<String>) {
    val isValid: Boolean get() = errors.isEmpty()
    
    fun throwIfInvalid() {
        if (!isValid) {
            throw IllegalArgumentException("配置验证失败:\n${errors.joinToString("\n")}")
        }
    }
}

// 使用验证器
fun validateConfig(config: Config) {
    val result = ConfigValidator(config).validate {
        require("app.name")
        require("app.version")
        
        requireInRange("server.port", 1024, 65535)
        requireNotEmpty("database.primary.url")
        
        requireMatch("database.primary.url", Regex("^jdbc:\\w+://.+$"))
    }
    
    if (result.isValid) {
        println("配置验证通过")
    } else {
        println("配置验证失败:")
        result.errors.forEach { println("  - $it") }
    }
}

最佳实践总结

1. 类型安全

  • 使用密封类定义类型
  • 充分利用Kotlin的类型推断
  • 为DSL元素提供明确的返回类型

2. 流畅的API设计

  • 使用infix函数简化语法
  • 利用操作符重载
  • 提供合理的默认值

3. 错误处理

  • 在编译时捕获尽可能多的错误
  • 提供清晰的错误消息
  • 支持配置验证

4. 扩展性

  • 设计可扩展的DSL结构
  • 支持嵌套和组合
  • 提供钩子函数进行自定义

5. 性能考虑

  • 使用内联函数减少开销
  • 避免不必要的对象创建
  • 懒加载和缓存配置

6. 文档和示例

  • 为DSL提供详细的文档
  • 包含丰富的使用示例
  • 提供迁移指南

这些真实案例展示了Kotlin DSL的强大能力,可以帮助你创建类型安全、表达力强且易于维护的领域特定语言。