8

我有一个代码,它将二分图作为输入并返回一个带有键“1”的映射,其值是“set1 中的节点”和键“2”的列表,其值是“set2 中的节点”列表。现在,地图是可变的。从理论上讲,我应该使用防御性副本来返回地图。但是,在这种情况下,真的需要吗?看起来有点矫枉过正。

前任:

class BiPartite {

   Graph graph;
   Map bipartite

   Bipartite(graph) {
      this.graph = graph;
   }

   void calcBipartite() {
     // calculate map 
   }

   Map getMap() {
     // should i make defensive copy ? Appears overkill. 
   }  
}
4

6 回答 6

6

这取决于 :)

  • 您可以相应地记录您的类,指定返回的 Map 是 BiPartite 对象可变状态的可变直接视图。但是,我不建议这样做。
  • Collections.unmodifiableMap(map)您可以使用in包装内部 MapgetMap() 记录它反映了 BiPartite 对象的可变状态。只要 BiPartite 对象不应该是线程安全的,这可能是一种有效的方法。如果客户想要将返回的 Map 保留为稳定的快照,她可以自己复制它。如果不需要,她可以从快速包装操作中受益。
  • 您可以随时返回完整副本。如果您实际上使 BiPartite 对象成为线程安全的,那将是最有意义的。在这种情况下,您还必须同步内部地图的所有操作(包括地图复制操作!)。

基本上它归结为:考虑应该如何使用 BiPartite 类及其方法,为此选择合适的实现,并清楚地记录类的行为及其背后的推理。

于 2013-08-09T06:49:00.743 回答
5

是的,您应该返回防御副本。如果您担心资源使用,您可以返回一个 Map ,它是您的私有地图的不可修改视图:

return Collections.unmodifiableMap(bipartite);
于 2013-08-09T06:42:02.060 回答
2

在解释模式和良好的编程实践时,“总是”这个词很少合适。这一切都取决于上下文。

在您的情况下BiPartite#getMap,方法和类本身是“包私有的”,因此客户端(您的代码的用户)将无法直接使用它。如果您知道您永远不会在该包的边界之外存储或返回该地图,那么可以肯定地说您不需要制作防御性副本。

于 2013-08-09T06:46:12.340 回答
1

是的,您应该这样做,因为否则客户端可以更改您班级的私有字段,从而使您的班级行为错误。

于 2013-08-09T06:38:55.120 回答
1

这取决于您的代码的约定。我遵循复制您想要保留的任何内容的惯例。即这是调用者的责任。

这更有效,但如果您不知道调用者将遵循此约定,则它并不健壮。

于 2013-08-09T06:40:07.547 回答
0

恕我直言,防御性副本是一件坏事,因为我遇到的大多数 java 框架都希望 getter 总是返回相同的值并快速完成。

如果你想避免你的代码行为不端,你应该只公开方法 calcBipartite() 并让它返回一个新计算的 Map。使用该方法的客户端必须决定如何使用创建的对象以及调用 calcBipartite() 的次数。

如果您是您的代码的唯一客户,则不应复制或包装。

于 2013-08-09T07:37:00.747 回答