Java 在我的对象中包含setter是否是一种良好的做法,即使我知道我永远都不会需要它

Java 在我的对象中包含setter是否是一种良好的做法,即使我知道我永远都不会需要它,java,object,setter,getter,Java,Object,Setter,Getter,今天出现了一个有趣的问题。为一个我知道永远不需要在构造函数之后重新设置的字段创建一个setter,这是一个很好的实践吗 当然,我理解使用私有字段和getter与公共字段的原因,这是有道理的,但是如果我不打算使用它,我真的应该成为setter吗 p.p.S.特别提到Java,尽管它实际上不应该与什么平台有关。通过不创建setter,只允许通过构造函数设置字段,您已经创建了一个不可变字段。创建类的实例后,该值将永远不会更改 注意:如果getter返回的值本身是可变的,那么上面的语句将不起作用。比方说

今天出现了一个有趣的问题。为一个我知道永远不需要在构造函数之后重新设置的字段创建一个setter,这是一个很好的实践吗

当然,我理解使用私有字段和getter与公共字段的原因,这是有道理的,但是如果我不打算使用它,我真的应该成为setter吗


p.p.S.特别提到Java,尽管它实际上不应该与什么平台有关。

通过不创建setter,只允许通过构造函数设置字段,您已经创建了一个不可变字段。创建类的实例后,该值将永远不会更改

注意:如果getter返回的值本身是可变的,那么上面的语句将不起作用。比方说,如果返回ArrayList的实例,则有人可以使用该引用添加和删除该列表中的项。请查看java.util.Collections.unmodifiableList来解决这个问题。如果在getter中返回java.util.Date,甚至可以更改它。要解决这个问题,可以使用JodaTime或其他类似的第三方日期类,或者等待Java8

在我和其他人看来,不可替换性是一件很好的事情,它可以使软件更少的bug,更容易维护。

这取决于情况

如果您的类是导出的API的一部分,并且您有理由相信API的客户机将有机会使用setter,那么包含setter可能是很有意义的

不过,这是关于接球手和二传手的真相

如果你的类有它们,那么你的类是可变的。可变数据和可变对象就是它们。如果您的设计意图指定此API始终是单线程的,那么您就没有问题

然而,即使在单线程应用程序中,您也应该尽可能创建不可变的对象。不可变对象的缺点是其中没有getter和setter的角色**请参见注释

一个折衷方案是构建器模式Bloch等人的有效Java第二版。。在此模式中,您使用可变辅助对象来设置对象的字段。。。然后,当您准备好时,您的助手对象使用您设置的数据来创建所需对象的不可变实例

当您的需求很简单并且不需要考虑争用或并发时,请使用可变对象。但请记住,对象的易变性越强,就越难对其状态进行推理。对其状态的推理越难,执行不变量和维护安全性就可能越困难。只有一个状态的对象可以解决几乎所有这些问题。特别是如果您的类是值类,您应该尽可能创建不可变对象

**注意:当然,可以为不可变类设置setter。在这种情况下,setter实例化一个新的不可变对象,从而保持其不可变性。String类依赖于此策略

为我知道在构造函数之后永远不需要重新设置的字段创建setter是一种好的做法吗

如果您事先知道这一点,那么请务必在代码中编写它。将该字段设为final,这样您就不会有任何疑问,因为编译器本身不允许您定义setter


这避免了编写方法,因为它可能是预期的,在我看来,这也是保持代码干净和可验证性的一个进步。您正在按原样声明内容,这也消除了测试值的不变性的需要。

您所定义的是一个只读字段,这是非常自然的事情。我想说没有理由建立一个二传者,所以不要这样做。事实上,这正是构建不可变类的方式——填充构造函数中的所有字段,然后它们就再也不能更改了。如果你决定将来你需要一个二传手,那么无论如何,把它放进去,但不要建造你认为你不需要的东西。这种反应的精神是正确的,而且是正确的。但是,必须记住,只读字段不一定是不变性的保证。如果字段是引用类型,并且getter将引用发布到外部客户端-或者-客户端在构造后维护对字段对象的引用。。。然后就有可能变异不可变对象。@scottb绝对!例如,作为列表的字段不应使用返回集合本身的getMyList公开。正如您所建议的,这将允许其他人更新该集合的内容。