将对象副本传递给方法 - 谁进行复制?

时间:2008-10-08 15:05:55

标签: oop

我有一个对象,我正在通过方法调用传递。假设我使用的语言只允许您通过引用传递对象,如Java或PHP。如果方法更改了对象,则会影响调用者。我不希望这种情况发生。所以我似乎需要制作一个对象的副本。

我的问题是:克隆对象的责任是什么?调用者在调用方法之前?或者被调用者,在它改变对象之前?

编辑:只是为了澄清,我希望这是此方法的合同的一部分 - 它永远不会修改原始对象。因此,似乎应该由制作副本的方法决定。但是,调用者无法保护不能正确执行此操作的方法。我想这是可以接受的 - 唯一的另一种选择似乎就是把它融入到语言中。

11 个答案:

答案 0 :(得分:5)

通常,来电者如果关注更改,则应制作副本。如果调用者不关心,该方法应该制作副本,如果它需要做一些它知道不应该持久的东西

答案 1 :(得分:1)

来电者。因为,有时您希望对对象本身进行更改,有时需要对副本进行更改。

虽然,我认为callee修改传递的对象是一种不好的做法(至少在面向对象的语言中)。这可能会导致许多不必要的副作用。

(在您之后)编辑:在这种情况下,被叫方有责任执行合同,因此有两种选择:

  • 被调用者根本不修改对象
  • 或被叫方复制该对象并随后使用该副本

答案 2 :(得分:1)

所以你想做类似

的事情

MyObject m = new MyObject(); MyObject n = MyObjectProcessor.process(m);?

做一些类似的事情对我来说似乎更简单 MyObject n = MyObjectProcessor.alter(m.clone());

哪里清楚谁在做谁的事情。您可以提出处理器类函数应该没有副作用的论点,即它应该在它改变状态的任何时候返回一个新对象,但是(AFAIK)在OO中并不是如此一致地跟随函数式编程。

上述内容可能是无害的,只要它有明确的命名和记录。

答案 3 :(得分:1)

我们可以看看红宝石的指导。他们用了!用于指示对象在就地修改的符号。因此,salary.add(10000)返回一个新对象,但salary.add!(10000)返回原始对象但已修改。您可以使用本地命名约定在Java或PHP中使用相同的想法。

答案 4 :(得分:0)

取决于,是否有任何理由可以在将来调用该方法,您希望调用者看到更改?如果是,那么调用者应该复制。否则被叫方应该成功。我会说第二种情况可能更常见。

答案 5 :(得分:0)

如果您让调用者克隆该对象,它可以让您灵活地不使用副本(通过不先克隆它),也意味着您不必返回一个新对象,您只需操作参考传入。

答案 6 :(得分:0)

我的第一反应是调用者的责任,但我认为这实际上取决于。

这取决于两种方法之间定义的合同。正在进行更改的方法应明确标识该事实并让调用者做出决定。或者,进行更改的方法应明确标识它不会对传递的对象进行任何更改,然后它将负责制作副本。

答案 7 :(得分:0)

我会说被调用者:它简化了调用,调用者不必担心给定对象的完整性。被呼叫者有责任保持诚信。

答案 8 :(得分:0)

我假设你会有类似const声明的东西。这将是编译器强制执行的,并且比创建对象的副本更有效。

答案 9 :(得分:0)

我认为调用者应该进行克隆,只是为了使命名更容易。您可以将方法命名为Foo()而不是CloneBarAndFooClone()。

比较

void RemoveZeroDollarPayments(Order order)

VS

Order CloneOrderAndRemoveZeroDollarPaymentsFromClone(Order order)

答案 10 :(得分:0)

如果不更改对象是方法契约的一部分,唯一的可能性是在方法内部进行复制。否则你是骗你的客户。

事实上,您实际上需要修改一个与给定的对象完全相同的对象,这只是一个不应该给调用者带来负担的实现细节。事实上,他甚至不需要了解这一点。