Scala 中为对象字段自动生成 getter/setter 的意义到底是什么?
众所周知,Scala 会自动为任何公共字段生成 getter 和 setter,并将实际字段变量设为私有。为什么它比仅仅公开该领域更好?
As we know, Scala generates getters and setters automatically for any public field and make the actual field variable private. Why is it better than just making the field public ?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先,这允许将公共 var/val 与(几个)def 交换,并且仍然保持二进制兼容性。其次,它允许重写派生类中的 var/val。
For one this allows swapping a public var/val with a (couple of) def(s) and still maintain binary compatibility. Secondly it allows overriding a var/val in derived classes.
首先,保持字段公开允许客户端读取和写入该字段。由于拥有不可变对象是有益的,因此我建议将该字段设置为只读(您可以在 Scala 中通过将其声明为“val”而不是“var”来实现)。
现在回到你的实际问题。如果您需要的不仅仅是简单的版本,Scala 允许您定义自己的 setter 和 getter。这对于维护不变量很有用。对于设置器,您可能需要检查字段设置的值。如果你将这个领域本身公开,你就没有机会这样做。
这对于声明为“val”的字段也很有用。假设您有一个 Array[X] 类型的字段来表示类的内部状态。客户端现在可以获取对此数组的引用并对其进行修改——同样,您没有机会确保保持不变量。但由于您可以定义自己的 getter,因此您可以返回实际数组的副本。
当您在 Java 中将引用类型设置为“final public”时,同样的论点也适用——客户端无法重置引用,但仍可以修改引用指向的对象。
相关说明:在 Scala 中通过 getter 访问字段看起来就像直接访问该字段。这样做的好处是,它允许访问字段和调用对象上不带参数的方法看起来像是同一件事。因此,如果您决定不再在字段中存储值,而是动态计算它,则客户端不必关心,因为它对他来说看起来是一样的——这被称为 统一访问原则
First, keeping the field public allows a client to read and write the field. Since it's beneficial to have immutable objects, I'd recommend to make the field read only (which you can achieve in Scala by declaring it as "val" rather than "var").
Now back to your actual question. Scala allows you to define your own setters and getters if you need more than the trivial versions. This is useful to maintain invariants. For setters you might want to check the value the field is set to. If you keep the field itself public, you have no chance to do so.
This is also useful for fields declared as "val". Assume you have a field of type Array[X] to represent the internal state of your class. A client could now get a reference to this array and modify it--again you have no chance to ensure the invariant is maintained. But since you can define your own getter you can return a copy of the actual array.
The same argument applies when you make a field of a reference type "final public" in Java--clients can't reset the reference but still modify the object the reference points to.
On a related note: accessing a field via getters in Scala looks like accessing the field directly. The nice thing about this is that it allows to make accessing a field and calling a method without parameters on the object look like the same thing. So if you decide you don't want to store a value in a field anymore but calculate it on the fly, the client does not have to care because it looks like the same thing to him--this is known as the Uniform Access Principle
简而言之:统一访问原则。
您可以使用 val 来实现超类中的抽象方法。想象一下来自某个想象的图形包的以下定义:
有两种可能的子类,一种是根据边界框定义圆,另一种是根据圆心和半径定义圆。借助 UAP,实现的细节可以完全抽象出来,并且可以轻松更改。
还有第三种可能性:lazy vals。这些对于避免一次又一次重新计算圆的边界非常有用,但是很难想象如果没有统一访问原则,如何实现惰性值。
In short: the Uniform Access Principle.
You can use a val to implement an abstract method from a superclass. Imagine the following definition from some imaginary graphics package:
There are two possible subclasses, one where the circle is defined in terms of a bounding box, and one where it's defined in terms of the centre and radius. Thanks to the UAP, details of the implementation can be completely abstracted away, and easily changed.
There's also a third possibility: lazy vals. These would be very useful to avoid recalculating the bounds of our circle again and again, but it's hard to imagine how lazy vals could be implemented without the uniform access principle.