在方法中操作对象而不是返回新对象?

时间:2011-02-21 13:24:33

标签: oop methods

假设我有一个用某种对象填充列表的方法。以下方法设计的优点和缺点是什么?

void populate (ArrayList<String> list, other parameters ...)

ArrayList<String> populate(other parameters ...)

我更喜欢哪一个?

这看起来像关于方法设计的一般问题,但我在google上找不到令人满意的答案,可能是因为没有使用正确的关键字。

4 个答案:

答案 0 :(得分:3)

第二个对我来说似乎更具功能性和线程安全性。在大多数情况下我更喜欢它。 (像所有规则一样,也有例外。)

populate方法的所有者可以返回一个不可变的List(为什么是ArrayList?)。

如果在populate方法中没有修改状态,那么它也是线程安全的。仅使用传入的参数,这些参数也可以是不可变的。

答案 1 :(得分:2)

除了@duffymo提到的,第二个更容易理解,因此使用:它的输入和输出是显而易见的。

答案 2 :(得分:1)

输入输出参数的优点:

  • 您不必创建任意数量的对象。在像C或C ++这样的语言中,分配和释放可能很昂贵,这可能是一个加分。在Java / C#中,没有那么多 - GC使得分配便宜并且释放除了不可见之外,因此创建对象并不是一件大事。 (你仍然不应该毫不犹豫地创建它们,但如果你需要它,那么开销并不像某些手动分配语言那么糟糕。)
  • 您可以指定列表的类型。如果您需要将该数组传递给您以后无法控制的其他代码,则可能会有好处。

缺点:

  • 可读性问题。

    • 在几乎所有支持函数参数的语言中,第一种情况假设为“对此列表中的条目执行某些操作”。修改args违反了最小惊讶原则。第二个被假定为“给我一个东西列表”,这就是你所追求的。
    • 每当你说“ArrayList”,甚至“List”时,你都会带来一些灵活性。您为API添加了一些开销。如果我不想在调用方法之前创建ArrayList怎么办?我不应该,如果方法的终身目的是给我一些条目。这是API的工作。
  • 封装问题:

    • 传递列表以填充的方法不能假定该列表的任何内容(即使它是一个列表;它可能为null)。
    • 传递列表的方法无法保证该方法对它的作用。如果它正常工作,当然,API文档可以说“此方法不会破坏现有条目”。但考虑到错误的可能性,这可能不值得信任。至少如果该方法返回自己的列表,则调用者不必担心之前的内容。并且它不必担心千里之外的错误会破坏它应该永远不会影响的数据。
  • 线程安全问题。

    • 该列表可能被另一个线程锁定,这意味着如果我们现在尝试锁定它,它可能会锁定应用程序。
    • 或者,如果没有锁定,它仍然可以被另一个线程修改,在这种情况下我们也不会被搞砸。除非您打算编写额外的代码来处理所有地方的并发修改异常。
    • 返回新列表意味着对该方法的每次调用都可以拥有自己的列表。没有线程可以弄乱另一个线程的返回值,除非该类的设计非常糟糕。

侧点:能够指定列表的类型通常会导致列表类型的依赖。注意你是如何在任何地方传递ArrayLists的。当你不需要时,你可以通过说“这是一个ArrayList”来绘制自己的角色,但当你将它传递给十几种方法时,你必须改变十几种方法。 (不完全相关,但只是略微相切。您可以将类型更改为List而不是ArrayList并摆脱这一点。但是,您传递的列表越多,您需要更改的位置就越多。)

简短版本:除非您有充分的理由,否则只有在您使用方法中列表的现有内容时才使用第一种语法。 IE:如果你正在修改它,或者用现有的值做某事。如果您打算返回条目列表,则返回条目列表

答案 3 :(得分:0)

出于多种原因,第二种方法是首选方法。 主要是因为函数签名更清晰,并显示了它的意图。

实际上建议您不要更改传递给函数的参数值,除非您明确将其标记为“out”参数。

在表达式

中也更容易使用

将来更容易改变。如果你想

,包括将其用于更具功能性的方法(用于线程等)
相关问题