【发布时间】:2010-11-26 07:47:21
【问题描述】:
我们知道,Scala 会自动为任何公共字段生成 getter 和 setter,并将实际的字段变量设为私有。为什么比仅仅公开这个领域更好?
【问题讨论】:
标签: scala
我们知道,Scala 会自动为任何公共字段生成 getter 和 setter,并将实际的字段变量设为私有。为什么比仅仅公开这个领域更好?
【问题讨论】:
标签: scala
一方面,这允许将公共 var/val 与(几个)def 交换,并且仍然保持二进制兼容性。其次,它允许在派生类中覆盖 var/val。
【讨论】:
首先,保持字段公开允许客户端读取和写入字段。由于拥有不可变对象是有益的,因此我建议将该字段设为只读(您可以在 Scala 中通过将其声明为“val”而不是“var”来实现)。
现在回到您的实际问题。如果您需要的不仅仅是普通版本,Scala 允许您定义自己的 setter 和 getter。这对于维护不变量很有用。对于设置器,您可能需要检查字段设置的值。如果您将字段本身公开,您就没有机会这样做。
这对于声明为“val”的字段也很有用。假设您有一个 Array[X] 类型的字段来表示您的类的内部状态。客户端现在可以获得对该数组的引用并对其进行修改——同样,您没有机会确保保持不变式。但是由于您可以定义自己的 getter,因此您可以返回实际数组的副本。
当您在 Java 中将引用类型的字段设为“最终公共”时,同样的论点也适用——客户端无法重置引用,但仍会修改引用指向的对象。
在相关说明中:在 Scala 中通过 getter 访问字段看起来像直接访问该字段。这样做的好处是它允许访问字段和调用对象上不带参数的方法看起来像同一件事。因此,如果您决定不再将值存储在字段中而是即时计算,客户不必关心,因为它对他来说看起来是一样的——这就是所谓的Uniform Access Principle
【讨论】:
简而言之:统一访问原则。
您可以使用 val 来实现超类的抽象方法。想象一下来自一些虚构图形包的以下定义:
abstract class circle {
def bounds: Rectangle
def centre: Point
def radius: Double
}
有两种可能的子类,一种是根据边界框定义圆,另一种是根据圆心和半径定义圆。多亏了 UAP,实现的细节可以完全抽象出来,并且很容易改变。
还有第三种可能性:惰性 val。这些对于避免一次又一次地重新计算我们的圆的边界非常有用,但是很难想象如果没有统一访问原则,如何实现惰性 val。
【讨论】: