今天出现了一个有趣的问题。为一个我知道在构造函数之后我永远不需要重新设置的字段设置一个伟大的设置器是一种好习惯吗?
PS我当然理解使用私有字段和getter与公共字段的原因,这是有道理的,但是如果我不打算使用它,我真的应该做一个setter吗?
PPS 专门指 Java,尽管它不应该在什么平台上真正重要。
通过不创建 setter 并且只允许通过构造函数设置字段,您创建了一个不可变字段。一旦你创建了你的类的一个实例,这个值就永远不会改变。
注意:如果您的 getter 返回的值本身是可变的,则上述语句将不成立。比如说,如果返回 的实例ArrayList
,则有人可以使用该引用来添加和删除该列表中的项目。看看java.util.Collections.unmodifiableList
解决这个问题。如果您在吸气剂中返回它,甚至java.util.Date
可以更改 a 。要解决这个问题,您可以使用 JodaTime(或其他类似的第三方日期类),或等待 Java 8。
在我的谦虚(和其他人并不总是那么谦虚)看来,不变性是一件很棒的事情,它可以减少软件的错误并且更容易维护。
这取决于。
如果您的类是导出 API 的一部分,并且您有理由相信您的 API 的客户端将有机会使用 setter,那么包含一个 setter 可能很有意义。
不过,这是关于 getter 和 setter 的真相。
如果您的班级有它们,那么您的班级是可变的。可变数据和可变对象就是它们。如果您的设计意图指定此 API 将始终是单线程的,那么您就没有问题。
但是,即使在单线程应用程序中,您也应该尽可能地创建不可变对象。不可变对象的缺点是其中没有 getter 和 setter 的角色(** 见注)。
一种折衷方案是 Builder 模式(Bloch 等人,Effective Java 2nd Ed.)。在此模式中,您使用可变的辅助对象来设置对象的字段......然后当您准备好时,您的辅助对象使用您设置的数据来创建您想要的对象的不可变实例。
当您的需求很简单并且不担心争用或并发时,请使用可变对象。但请记住,您的对象越易变,就越难推断其状态。并且越难对其状态进行推理,执行不变量和维护安全性的潜在难度就越大。只能具有一种状态的对象几乎可以解决所有这些问题。特别是如果你的类是一个值类,你应该尽可能地创建不可变对象。
(**) 注意:当然,可以为不可变类设置设置器。在这种情况下,setter 实例化一个新的不可变对象,从而保持其不变性。String 类依赖于这种策略。
为我知道在构造函数之后永远不需要重新设置的字段创建设置器是一种好习惯吗?
如果您事先知道这一点,那么请务必将其写入您的代码中。制作那个 field final
,然后你就不会有任何疑问了,因为编译器本身不会让你定义一个 setter。
在我看来,这避免了“因为它可能是预期的”而编写方法,并且在保持代码清洁和可验证方面也向前迈进了一步。您按原样声明事物,这也消除了测试值的不变性的需要。