有没有一种方法可以“禁用”主要构造函数或强制用户始终使用次要构造函数?

时间:2020-09-11 18:38:11

标签: kotlin

示例:

data class Car (
    val type: TypeEnum,
    val brand: BrandEnum,
    val modelNumber: Int) 
{
    constructor(val type: TypeEnum, 
                val brand: BrandEnum,
                val input: String) : this (
        type,
        brand,
        Valdidator.validateModelNumber(input)
    )
}

在上面的代码中,方法validateModelNumber()验证原始输入,如果型号具有无效格式,则引发异常。我想强迫用户每次要创建Car对象时都要使用此构造函数。

本质上:我想确保没有无效的Car对象存在,同时仍使代码尽可能不变。

2 个答案:

答案 0 :(得分:1)

您可以改用init块。像这样

data class Car (
    val type: TypeEnum,
    val brand: BrandEnum,
    val modelNumber: Int)
{
    init {
        Valdidator.validateModelNumber(input)
    }
}

答案 1 :(得分:0)

如果只需要在主构造函数中指定的参数/属性,则使用init块进行验证(根据另一个答案)可以很好地工作。但是,还有其他方法。

如果您不希望其他代码使用主构造函数,则可以通过更改以下内容使其成为private

data class Car(

收件人:

data class Car private constructor(

然后,您可以将公共二级构造器留给其他类使用,如问题所示。但是,这仍然有些限制,因为在调用主构造函数之前您无法进行任何认真的处理。

因此通常的模式是在随播对象中具有私有构造函数和工厂方法。这更加灵活:您可以在调用实际的构造函数之前和之后进行任何数量的处理;您甚至可以返回缓存的实例,子类实例等。

通过使用适当的参数将其实现为operator fun invoke(),可以使这些外观像构造函数一样。在这种情况下,可能看起来像这样:

data class Car private constructor(
    val type: TypeEnum,
    val brand: BrandEnum,
    val modelNumber: Int) 
{
    companion object {
        operator fun invoke(type: TypeEnum, brand: BrandEnum, input: String)
            = Car(type, brand, Validator.validateModelNumber(input))
    }
}

然后您可以使用以下示例创建实例:

Car(TypeEnum.SPORTS, BrandEnum.ASTON_MARTIN, "DB5")

看起来像普通的构造函数。