如果类是继承的,请使用自定义设置器

时间:2019-08-08 17:58:26

标签: inheritance kotlin

我有一个包含抽象方法和主要构造函数的抽象类

abstract class Article constructor(
    text: String
) {

    var text: String = text
        set(value) {
            assert(isValid(value))
            field = value
        }

    val isValid: Boolean = isValid(this.text)
    abstract fun isValid(text: String): Boolean
}

我还有另一个继承/扩展main的类。

class ShortArticle(
    text: String
) : Article(string) {
    override fun isValid(text: String) = text.length == 11 
}

我需要验证所创建的每篇文章,并且还需要从Article抽象类继承。

但是,如果我要像这样创建子类:

ShortArticle("hello world blahlblahslab")

未调用验证(自定义设置器)。 在这种情况下调用它:

var article = ShortArticle("hello world blahlblahslab")
article.text = "new text that is validated"

我尝试创建在分配过程中验证的函数。

  

var text:字符串=验证(文本)

但是它作为文本传递给ShortArticle null

2 个答案:

答案 0 :(得分:2)

以您的方式进行分配时,它不会触发自定义设置器。它与Java类似,只是直接设置它并绕过setter。如果要触发设置器,则需要从init块或构造函数中调用它。但是,由于您仅使用主构造函数,因此我将使用init块。

由于我不了解自己的问题,这是合法的:

abstract class Article constructor(
    text: String
) {

    var text: String


    init { this.text = text }

    val isValid: Boolean = isValid(this.text)
    abstract fun isValid(text: String): Boolean
}

但这不是:

abstract class Article constructor(
    text: String
) {

    var text: String
        set(value) {
            assert(isValid(value))
            field = value
        }
    init { this.text = text }

    val isValid: Boolean = isValid(this.text)
    abstract fun isValid(text: String): Boolean

}

但是您可以通过声明如下文本来部分解决此问题:

var text: String = ""
    set(value) {
        assert(isValid(value))
        field = value
    }

请注意,由于初始化的顺序,init块 处于文本变量的初始化之后,但isValid变量的初始化之前。否则,isValid会离开""默认值,并且字段本身为false。但是,我没有看到该字段的任何值-您具有isValid函数,该函数的作用类似于该方法的实时更新版本。如图所示,如果文本字段,isValid字段和init块的顺序是除此以外的任何内容:

var text: String = ...
    set(value) { ... }
init { this.text = text; }

val isValid: Boolean = isValid(this.text)

它将失败。 init块之后的text将无法编译,而init块之前的isValid将导致使用isValid而不是""的实际值进行text调用

就设计而言,我会选择这样的东西:

abstract class Article constructor(text: String) {

    var text: String = "" // required default value to enable initialization in the init block 
        set(value) {
            assert(isValid(value)) // checks the validity
            field = value
        }
    init { this.text = text } // assigns 

    protected abstract fun isValid(text: String): Boolean 

}

由于您设计类的方式,如果无效,它将引发异常。另外,isValid是最终的,这意味着它不会改变,使其毫无意义。我还使isValid函数受到保护,因为它不是静态函数。除非初始化该类,否则它将无法用于验证,这时无论如何检查都为时已晚。

答案 1 :(得分:1)

您可以向Article构造函数添加显式设置值。然后将调用验证

abstract class Article constructor(
    text: String
) {
    var text: String = ""
        set(value) {
            assert(isValid(value))
            field = value
        }

    init {
        this.text = text
    }

    val isValid: Boolean = isValid(this.text)
    abstract fun isValid(text: String): Boolean
}