为什么Kotlin隐式调用属性的getter和setter方法?

时间:2020-06-22 22:45:42

标签: kotlin

当您尝试访问属性时,Kotlin隐式调用属性的getter / setter函数的目的是什么?获取器和设置器已经不是要使用它们就可以轻松调用它们的意义了吗? Kotlin的版本基本上只是使用“字段”标识符引入了额外的复杂性,并引入了如下所示的怪异现象,其中对象的行为可能与预期的接口不同:

interface Counter {
    var count: Int
    fun increment() {
        count = count + 1
    }
}

class WeirdCounter: Counter {
    override var count: Int = 0
        get() = field
        set(value) {println("ignore the value")}
}

只是试图了解其背后的意图。

1 个答案:

答案 0 :(得分:4)

Kotlin使用getter和setter来实现属性的方式基本上是许多其他语言中的常用做法(也是最佳做法)。

“裸”字段(如Java中一样)非常简单,清晰且易于使用;但裸字段有问题

  • 它们公开了实现细节(字段,尤其是它的类型),以防止将来被更改。

  • 他们不允许类控制自己的状态。

当然,对于简单的值类来说,这些不是问题。但是对于更复杂的类,它们可能是一个真正的问题。

例如,您可能想要更改类存储状态的方式(例如,用long替换BigDecimal),但是如果该类是流行图书馆的公共接口的一部分,那么成千上万的用户会非常恼火。

或者,如果可以确保将String属性始终以小写形式存储而没有前导或尾随空格,那将真的很方便。但是,如果使用“裸”属性,则无法强制执行。

因此通常的模式是拥有一个私有字段,并且只能从类本身(由您控制​​)内部进行访问; 并提供访问器方法

这使您可以完全控制。您可以更改内部表示形式,只要您更新访问器方法以根据需要转换为新表单或从新表单转换为新表单。然后,您的设置者可以执行任何规范化,格式化或任何其他操作来对状态施加任何限制。

但是,在Java之类的语言中,这比简单的字段更为尴尬和漫长:访问器方法将单行字段转换为七行(不包括空行,不包括文档注释,因此可能更像是将3行变成21行。而且,尽管调用getter方法(使用get())仅比引用字段多几个字符,但调用setter却比简单的赋值要直观得多。

结果是开发人员要么做正确的事情,然后用样板填充他们的课程(包括对可维护性和错误风险的所有暗示),要么他们不理会上面的问题,也不会冒险。

但是,

科特琳提供了两全其美的功能:一个简单的属性外观就像一个字段,无论是在定义时还是在访问时。这样您就可以获得简洁,简洁,清晰的代码。但这是已实现的私有后备字段(如果需要)和访问器方法,因此您也可以获得这些优点。而且,如果您需要添加验证或更改表示形式或记录所有访问权限或其他操作,则可以选择用自己的实现替换默认访问器。

您的WeirdCounter示例很奇怪,但没有您想像的那么可怕(或不太可能)。在面向对象的语言中,类是其自身状态的主人,而其他类通常也不知道它们的内部。 (这样一来,他们就不会受到内部更改的影响)。如果一个班级需要在二传手中做一些违反直觉的事情,那只会是一个担心,如果它违反了班级的契约-但这将是一个错误,应该变成在测试中很明显,甚至在其他地方也没有。

在实践中,班级控制访问其状态的能力比班级使用班级进行愚蠢或恶意(这很容易发现)的风险更为重要。