java:当你只有一个接口时如何制作防御性拷贝

时间:2009-09-22 04:26:45

标签: java interface copy

如果一个对象引用另一个对象,我知道制作传入对象的副本以保留封装是个好主意。但是,如果所有对象都知道传入的对象是它实现了一个接口呢?

例如,如果我有一个在其构造函数中采用FilenameFilter实现的对象,那么当我所知道的是它实现FilenameFilter时,如何制作它的防御性副本?我是否不得不求助于反思?

3 个答案:

答案 0 :(得分:6)

处理此类问题时,最好的办法是尽可能多地使对象成为不可变对象,这意味着它们在创建后无法修改。如果你需要修改它们,你可以创建一个新的原始版本。

这也适用于多线程。

作为一般规则,可变对象不被视为“最佳实践”。你不能完全消除它们,但正如乔什布洛赫所说,赞成不变性。

话虽如此,没有任何方法可以以任何形式保证深层复制(这是你需要的)。如果您只是简单地传入一个接口,那么您唯一的选择就是反映某种形式或将副本复制到另一个实现相同接口的对象(如果可能的话)。

答案 1 :(得分:2)

首先,制作防御性副本并不总是一个好主意。您只希望使用不能强制执行业务逻辑所需合同的可变类(例如集合)来执行此操作。

你的是一个很好的例子。 FilenameFilter是不可变的 - 没有什么可以通过该接口改变它。随意随意传递它。唯一可能的问题是线程,这很少是一个问题。

更通用的解决方案(对于实际上像集合这样的问题的类)将是将集合包装在类中而不是复制它。如果将它包装在业务逻辑类中,则可以限制访问,直到您确定它不会破坏业务逻辑规则,然后随时随地将其传递。

你会注意到JDK几乎从不传递集合。这是有目的的,也是您正在考虑的“复制”模式的确切原因。通常JDK会传递一个数组,大多数集合都有一种相当简单的方法来生成要传递的内容副本。

复制对象实际上非常罕见 - 集合和数组是需要关注的主要对象。大多数其他物体如果设计得相当均匀,就可以很好地保护自己。

答案 2 :(得分:0)

我首先要仔细考虑防御性副本是否真的有必要。如果这不是与安全相关的问题,那么在这种情况下听起来似乎并非严格必要。

然后假设副本是严格必要的,我将定义FileFilter的子接口,该子接口定义具有适当语义的复制方法。在您提到的构造函数中使用该接口而不是FileFilter,传递实现接口的FileFilters,并安排上述构造函数在适当的时间调用copy方法。

(或者,您可以使用Object.clone(),具体取决于应用的应用包结构。)