You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中如何让data class参数支持Int或BigDecimal两种类型

Kotlin实现Money类支持Int/BigDecimal双类型入参的方案

方案1:密封接口实现(更推荐,类型安全、易扩展)

该方案通过密封接口约束公共能力,不同入参类型对应独立的实现类,完全解耦不同类型的toSmallestUnit逻辑,符合开闭原则。

import java.math.BigDecimal

// 币种枚举示例
enum class CurrencyCode {
    USD, EUR
}

sealed interface Money {
    val currencyCode: CurrencyCode
    fun toSmallestUnit(): Int

    // Int类型入参的实现类
    data class IntAmount(
        val amount: Int,
        override val currencyCode: CurrencyCode
    ) : Money {
        override fun toSmallestUnit(): Int = when (currencyCode) {
            CurrencyCode.USD -> amount * 100
            CurrencyCode.EUR -> amount * 100
        }
    }

    // BigDecimal类型入参的实现类
    data class BigDecimalAmount(
        val amount: BigDecimal,
        override val currencyCode: CurrencyCode
    ) : Money {
        override fun toSmallestUnit(): Int = when (currencyCode) {
            CurrencyCode.USD -> amount.multiply(BigDecimal(100)).intValueExact()
            CurrencyCode.EUR -> amount.multiply(BigDecimal(100)).intValueExact()
        }
    }

    companion object {
        // 重载工厂方法,对外暴露统一的调用入口,和普通构造方法使用方式一致
        operator fun invoke(amount: Int, currencyCode: CurrencyCode): Money = IntAmount(amount, currencyCode)
        operator fun invoke(amount: BigDecimal, currencyCode: CurrencyCode): Money = BigDecimalAmount(amount, currencyCode)
    }
}

使用示例

// 两种入参类型都支持
val intMoney = Money(20, CurrencyCode.USD)
val decimalMoney = Money(BigDecimal("20.55"), CurrencyCode.EUR)

// 自动匹配对应类型的toSmallestUnit实现
println(intMoney.toSmallestUnit()) // 输出2000
println(decimalMoney.toSmallestUnit()) // 输出2055

方案2:单一DataClass实现(适合不需要扩展的轻量场景)

如果要求对外只暴露一个Money数据类,可以通过私有主构造+公开次构造重载实现,用私有字段标记入参类型,分支处理toSmallestUnit逻辑。

import java.math.BigDecimal

enum class CurrencyCode {
    USD, EUR
}

data class Money private constructor(
    val amount: BigDecimal,
    val currencyCode: CurrencyCode,
    // 私有字段标记入参类型,外部不可访问
    private val isIntInput: Boolean
) {
    // Int类型入参的构造方法
    constructor(amount: Int, currencyCode: CurrencyCode) : this(
        amount = amount.toBigDecimal(),
        currencyCode = currencyCode,
        isIntInput = true
    )

    // BigDecimal类型入参的构造方法
    constructor(amount: BigDecimal, currencyCode: CurrencyCode) : this(
        amount = amount,
        currencyCode = currencyCode,
        isIntInput = false
    )

    fun toSmallestUnit(): Int = if (isIntInput) {
        // Int入参对应的实现逻辑
        when (currencyCode) {
            CurrencyCode.USD -> amount.intValueExact() * 100
            CurrencyCode.EUR -> amount.intValueExact() * 100
        }
    } else {
        // BigDecimal入参对应的实现逻辑
        when (currencyCode) {
            CurrencyCode.USD -> amount.multiply(BigDecimal(100)).intValueExact()
            CurrencyCode.EUR -> amount.multiply(BigDecimal(100)).intValueExact()
        }
    }
}

方案选择建议

  • 优先选密封接口方案:后续如果要新增Long、Double等其他入参类型,只需要新增实现类即可,不需要修改原有逻辑,也不存在分支判断遗漏的风险
  • 仅当业务场景非常稳定,不会扩展其他入参类型时,选择单一DataClass方案

内容的提问来源于stack exchange,提问作者Leff

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.30 12:36:01