考虑对象封装,应该干将返回一个不可改变的属性?(Considering object encapsu

2019-06-26 04:30发布

当一个getter返回的属性,比如返回一个List其他相关的对象,应该是列表,它的对象是不可改变的,以防止类之外的代码,改变这些对象的状态,不知道主父对象?

例如,如果一个Contact对象,有一个getDetails getter,它返回一个ListContactDetails对象,那么任何代码调用该消气:

  1. 可以删除ContactDetail从该列表中没有的对象Contact对象知道这一点。
  2. 可以改变每个ContactDetail对象没有Contact对象知道这一点。

所以,我们应该做些什么吗? 我们应该只相信调用代码,并返回容易可变对象,或者去艰难地做出了不可变类为每个可变类?

Answer 1:

这是你是否应该在你的代码的“防御性”的问题。 如果你是你们班的(唯一的)用户,你相信你自己,然后通过各种手段无需不变性。 但是,如果这个代码需要工作不管是什么,或者你不信任你的用户,那么请即外在不可改变的一切。

我创建也就是说,很多特性是可变的。 一个偶然的用户搞砸这件事,但话又说回来,这是他/她的错,因为它清楚地记载,突变不应通过经干将接受可变对象发生。



Answer 2:

这取决于上下文。 如果该列表旨在是可变的,有在塞满了主类的API使用方法的变异它时,列表中包含了其自身的一个非常好的API是没有意义的。

但是,如果主类不能突变应对,那么你就需要返回不可变列表 - 在列表中的条目可能还需要为不可变的自己。

不要忘了,虽然,你可以返回,知道如何通过是否触发事件或直接执行任何必要的行动安全应对突变的请求,自定义列表实现。 事实上,这是用一个内部类的好时机一个典型的例子。



Answer 3:

如果你调用代码的控制,然后最重要的是,你做出的选择是在所有适当的地方记录良好。



Answer 4:

在收集的特定情况下,列表中,设置或地图在Java中,很容易返回一个不可改变的视图来使用类return Collections.unmodifiableList(list);

当然,如果有可能的后备数据仍将被修改,然后你需要做的清单的完整副本。



Answer 5:

约书亚布洛赫在他出色的“有效的Java”一书中说,回到这样的事情时,你应该始终防守副本。 这可能是一个有点极端,特别是如果ContactDetails对象是不可复制的,但它始终是安全的方式。 如有疑问总是青睐代码安全性能上 - 除非分析表明,cloneing是一个真正的性能瓶颈。

实际上,有保护的几个层次,您可以添加。 您可以简单地返回成员,基本上是提供其他任何类访问类的内部结构。 非常不安全,但在公平性广泛进行。 这也将在稍后如果你想改变的内部,使得ContactDetails被存储在一组引起你的麻烦。 您可以返回在内部列表到同一对象的引用新创建的列表。 这是更安全的 - 其他类不能删除或添加到列表中,但它可以修改现有的对象。 再次返回与ContactDetails对象的副本新创建的列表。 这是安全的方式,但可能很昂贵。

我会做一个更好的办法。 不要返回一个列表在所有-而不是在一个列表返回一个迭代 。 你不必创建一个新的列表方式(列表中包含了一个方法来获得一个迭代器),但外部类不能修改的列表。 它仍然可以修改的项目,除非你自己写的迭代器作为需要一个克隆的元素。 如果以后改用其他集合在内部它仍然可以返回一个迭代器,因此无需外部变化。



Answer 6:

取决于上下文,真的。 但是总体来说,是的,应尽可能(返回数组副本 ,返回各地系列 S等只读包装 )写入保护功能代码。 在任何情况下,应明确记载



Answer 7:

我用来返回列表的只读版本,或者至少一个拷贝。 但是,列表中包含的每个对象都必须是可编辑的,除非他们是通过设计不变。



Answer 8:

我想你会发现它是非常罕见的,每gettable是不可改变的。

你可以做的是,当一个属性是这样的对象之内改为触发事件。 不是一个完美的解决办法。

文档可能是最务实的解决方案;)



Answer 9:

你的当务之急应该是有规律可循的德米特或“告诉不问”; 告诉对象实例做什么如

contact.print( printer ) ;  // or
contact.show( new Dialog() ) ; // or
contactList.findByName( searchName ).print( printer ) ;

面向对象的代码告诉对象做的事情。 程序代码获取信息,然后作用于这些信息。 询问对象,以揭示其内部断裂封装的细节,它是程序代码,而不是健全面向对象编程和威尔已经表示,它是一个有缺陷的设计。

如果遵循迪米特法则接近中的对象的状态的任何变化发生通过其定义的接口,因此副作用是公知的和控制。 你的问题消失。



Answer 10:

当我开始了我仍然严重地隐藏你的数据OO校长LOL的影响。 我会坐下来思考,如果有人改变由财产公开的对象之一的状态会发生什么。 我应该让他们只对外部呼叫者读? 我不应该揭露他们呢?

收藏拿出这些担忧到了极致。 我的意思是,有人可以删除集合中的所有对象,而我不看!

我终于意识到,如果你的对象坚持自己的外部可见的性质和类型,如果有人摸了一个不好的地方你去热潮,这种紧密的依赖关系,你的架构是有缺陷的。

有正当的理由,让您的只读外部属性和它们的类型不变。 但是,这是极端情况,不是典型的一个,恕我直言。



Answer 11:

首先,getter和setter方法是不好的面向对象的指示。 一般来说OO的思想是你问的对象为你做些什么。 设置和获取是相反的。 太阳应该已经找到了实现的Java bean,这样人们就不会去接这个模式,认为这是“正确”的一些其他方式。

其次,每个对象你应该是世界本身 - 通常,如果你要使用getter和setter方法,他们应该返回相当安全独立的对象。 这些对象可能是因为他们只是第一类对象或可能不会是一成不变的。 另一种可能性是,他们返回原生类型,其始终不变的。 所以说“应该getter和setter方法返回的东西不变”没有什么太大的意义。

至于制作不变对象本身,你应该事实上总是让你的对象最终内成员,除非你有很强的理由不(最终应该是默认的,“可变”应该是,将覆盖默认关键字)。 这意味着,只要有可能,对象将是不变的。

至于你可能会绕过预定的准对象的事情,我建议你换类似的东西一起去为自己的班级,自己的方法值集合和组。 我实际上从未绕过未受保护的集合,只是因为你没有给它如何使用的任何指导/帮助这里使用一个精心设计的对象应该是显而易见的。 安全性也是因为允许集合某人访问内部类使得它几乎不可能保证在班上总是会有效的一个因素。



文章来源: Considering object encapsulation, should getters return an immutable property?
标签: java oop