我有一个代码,它以二分图作为输入,返回一个带键“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.
}
}
答案 0 :(得分:6)
取决于:)
Collections.unmodifiableMap(map)
和文档中的getMap()
封装内部地图,以反映BiPartite对象的可变状态。只要BiPartite对象不应该是线程安全的,那么这可能是一种有效的方法。如果客户想要将返回的Map保持为稳定的快照,她可以自己复制它。如果不需要,她可以从快速包装操作中受益。基本上归结为:考虑如何使用BiPartite类及其方法,为此选择合适的实现并清楚地记录类的行为及其背后的推理。
答案 1 :(得分:5)
是的,你应该返回一份防御性副本。如果您担心资源使用,可以返回一张不可修改的私人地图视图:
return Collections.unmodifiableMap(bipartite);
答案 2 :(得分:2)
在解释模式和良好的编程实践时,“总是”这个词很少适用。这一切都取决于具体情况。
在您的情况下,BiPartite#getMap
方法和类本身是“包私有”,因此客户端(代码的用户)将无法直接使用它。如果你知道你从未在该套餐的边界之外存储或返回该地图,那么可以很自然地说你不需要制作防御性副本。
答案 3 :(得分:1)
是的,你应该, 因为否则客户可以更改班级的私人领域,使你的班级表现错误。
答案 4 :(得分:1)
这取决于代码的约定。我按照惯例复制你想要保留的任何内容。即是来电者的责任。
这样效率更高,但如果您不知道调用者将遵循此约定,则效果不佳。
答案 5 :(得分:0)
防御性拷贝是一件坏事,因为我遇到的大多数java框架都希望getter能够始终返回相同的值并快速完成。
如果你想从你的代码的行为不端的客户端中保存,你应该只暴露方法calcBipartite()并让它返回一个新计算的Map。使用该方法的客户端必须决定如何使用创建的对象以及调用calcBipartite()的次数。
如果您是代码的唯一客户,则不应复制或包装。