Kotlin 带继承与必填参数的数据结构最佳实践及实现方案
问题原因说明
- 原代码父类
amount字段声明为String类型,和你期望调用时传入的数值类型12不匹配 - 子类继承父类时没有透传父类要求的必填参数和可选参数,导致实例化子类时无法传入父类定义的参数
- 密封类本身就不允许直接实例化,天然满足「仅允许实例化子类对象」的要求,不需要额外限制
基础实现方案(无工厂模式,匹配你期望的调用写法)
直接在子类声明时透传父类的所有参数,固定的type参数由子类内部赋值即可:
enum class SupportedTypes { ONE, TWO } sealed class TransferObject( val type: SupportedTypes, val system: String = "sys1", val amount: Int, val awaitReceipt: Boolean = true ) { data class TransferObject_ONE( val system: String = "sys1", val amount: Int, val awaitReceipt: Boolean = true, val obligatoryString: String ) : TransferObject(SupportedTypes.ONE, system, amount, awaitReceipt) data class TransferObject_TWO( val system: String = "sys1", val amount: Int, val awaitReceipt: Boolean = true, val obligatoryInt: Int ) : TransferObject(SupportedTypes.TWO, system, amount, awaitReceipt) }
调用方式完全符合你的预期:
val obj1 = TransferObject.TransferObject_ONE(system = "sys3", obligatoryString = "myString", amount = 12) // 也可以省略有默认值的参数 val obj2 = TransferObject.TransferObject_TWO(amount = 20, obligatoryInt = 5)
该方案的优势:
- 编译期强制校验所有必填参数,缺参会直接编译报错,不需要运行时判断
- 没有额外封装成本,调用写法完全匹配需求
- 天然限制仅能实例化子类,父类无法直接创建对象
工厂模式适用场景与实现
如果你的场景有以下需求,可以选择叠加工厂模式:
- 实例化前需要统一做参数校验(比如amount必须大于0、system不能为空)
- 需要隐藏子类实现,不对外暴露子类类名
- 实例化时需要统一注入日志、埋点等横切逻辑
工厂模式实现示例:
enum class SupportedTypes { ONE, TWO } sealed class TransferObject( val type: SupportedTypes, val system: String = "sys1", val amount: Int, val awaitReceipt: Boolean = true ) { // 子类构造器私有化,仅允许通过工厂方法实例化 data class TransferObject_ONE private constructor( val system: String = "sys1", val amount: Int, val awaitReceipt: Boolean = true, val obligatoryString: String ) : TransferObject(SupportedTypes.ONE, system, amount, awaitReceipt) data class TransferObject_TWO private constructor( val system: String = "sys1", val amount: Int, val awaitReceipt: Boolean = true, val obligatoryInt: Int ) : TransferObject(SupportedTypes.TWO, system, amount, awaitReceipt) companion object { fun createOne( system: String = "sys1", amount: Int, awaitReceipt: Boolean = true, obligatoryString: String ): TransferObject { require(amount > 0) { "amount必须大于0" } require(system.isNotBlank()) { "system不能为空" } return TransferObject_ONE(system, amount, awaitReceipt, obligatoryString) } fun createTwo( system: String = "sys1", amount: Int, awaitReceipt: Boolean = true, obligatoryInt: Int ): TransferObject { require(amount > 0) { "amount必须大于0" } return TransferObject_TWO(system, amount, awaitReceipt, obligatoryInt) } } } // 调用示例 val obj = TransferObject.createOne(system = "sys3", amount = 12, obligatoryString = "myString")
内容的提问来源于stack exchange,提问作者David
相关产品推荐
相关产品推荐

