我会说这实际上是依赖于语言的。如果你原谅我,我会稍微谈谈C#,因为我认为它将有助于回答这个问题。
我不确定你是否熟悉C#,但它的设计,工具等都非常直观且对程序员友好。
C#的一个功能(也存在于Python,D等中)可以帮助它,这是属性;属性基本上是一对方法(getter 和/或 setter),它们在外部看起来就像一个实例字段:你可以分配给它,你可以像一个实例变量一样从中读取。
当然,在内部,这是一种方法,它可以做任何事情。
但是C#数据类型有时也有GetXYZ()和SetXYZ()方法,有时它们甚至直接公开它们的字段...这就引出了一个问题:你如何选择什么时候做什么?
Microsoft 对 C# 属性以及何时使用 getters/setters 有很好的指导原则:
属性的行为应像字段一样;如果方法不能,则不应将其更改为属性。在以下情况下,方法优于属性:
- 该方法执行耗时的操作。该方法明显慢于设置或获取字段值所需的时间。
- 该方法执行转换。访问字段不会返回它存储的数据的转换版本。
- 该方法具有可观察到的副作用。检索字段的值不会产生任何副作用。
Get
- 执行顺序很重要。设置字段的值不依赖于其他操作的发生。
- 连续调用该方法两次会产生不同的结果。
- 该方法是静态的,但返回一个可由调用方更改的对象。检索字段的值不允许调用方更改字段存储的数据。
- 该方法返回一个数组。
请注意,这些准则的整个目标是使所有属性在外部看起来像字段。
因此,使用属性而不是字段的唯一真正原因是:
- 你想要封装,yada yada。
- 您需要验证输入。
- 您需要从其他位置检索数据(或将数据发送到其他位置)。
- 您需要正向二进制 (ABI) 兼容性。我是什么意思?如果您将来决定需要添加某种验证(例如),那么将字段更改为属性并重新编译库将破坏依赖于它的任何其他二进制文件。但是,在源代码级别,什么都不会改变(除非你正在获取地址/引用,否则你可能不应该这样做)。
现在让我们回到Java/C++和不可变数据类型。
其中哪一点适用于我们的方案?
- 有时它不适用,因为不可变数据结构的全部意义在于存储数据,而不是具有(多态)行为(例如,String数据类型)。
如果您要隐藏数据并且不执行任何操作,那么存储数据有什么意义?
但有时它确实适用(例如,假设你有一个不可变的树) - 你可能不想公开元数据。
但是在这种情况下,您显然会隐藏您不想公开的数据,并且您一开始就不会问这个问题!:)
- 不适用;没有要验证的输入,因为没有任何变化。
- 不适用,否则您不能使用字段!
- 可能适用,也可能不适用。
现在Java和C++没有属性,但方法取而代之 - 所以上面的建议仍然适用,没有属性的语言的规则变成了:
如果 (1) 您不需要 ABI 兼容性,并且 (2) 您的 getter 的行为就像一个字段(即它满足上面 MSDN 文档中的要求),那么您应该使用字段而不是 getter。
重要的是要认识到,这些都不是哲学的。所有这些指南都基于程序员的期望。显然,一天结束时的目标是(1)完成工作,以及(2)保持代码的可读性/可维护性。上面的指南已经发现有助于实现这一目标 - 你的目标应该是做任何适合你喜欢的事情来实现这一目标。