Java 方法中的副作用

sva*_*605 5 java

这可能是一个微不足道的问题,但我需要澄清一下……有一本书叫做 Clean Code 说我们的方法应该很小,最好是 5-10 行长。为了实现这一点,我们需要将我们的方法拆分成更小的方法。例如,我们可能有如下所示的 someMethod() 。比方说,修改“示例”需要 5 行,我决定将它移到一个单独的方法中,在那里修改“示例”并将其返回给 someMethod()。通过这样做, someMethod() 变得更小且更易于阅读。这很好,但是有一种叫做“副作用”的东西,它说我们不应该将对象传递给另一个方法并在那里修改它。至少,有人告诉我这是一个坏主意)但是我在 Clean Code 中没有看到任何禁止我这样做的内容。

public Example someMethod() {

    // ... different lines here

    Example example = new Example();
    example = doSomethingHere(example, param1, param2, ...);    

    // ... different lines here

    return example;
}

private Example doSomethingHere(Example example, 'some additional params here') {

    // ... modify example's fields here ...

    return example;
}
Run Code Online (Sandbox Code Playgroud)

那么,我是否允许以这种方式拆分方法或禁止这种副作用,而是应该处理一个相当长的方法,该方法肯定违反了 Clean Code 关于短方法的规则?


更新(子方法的更具体名称)

public Example someMethod() {

    // ... different lines here

    Example example = new Example();
    example = setExampleFields(example, param1, param2, ...);    

    // ... different lines here

    return example;
}

private Example setExampleFields(Example example, 'some additional params here') {

    // ... modify example's fields here ...

    return example;
}
Run Code Online (Sandbox Code Playgroud)

Jim*_*Jim 5

我们不应该将对象传递给另一个方法并在那里修改它。

谁说的?这实际上是一个很好的实践,以便以形成“配方”的方式分割您的函数,并具有确切知道如何正确填充对象的特定函数。
不推荐的(并且可能您获得建议的来源误解了此规则)是定义公共 API 并修改参数。用户很高兴他们的论点不被修改,因为这样可以减少意外。一个例子是将数组作为参数传递给方法。


Jeu*_*arg 5

正如 JB Nizet 评论的那样,如果它是唯一的效果,那么它实际上并不是副作用,因此任何“所有副作用都是不好的”的笼统声明并不适用于此。

不过,主要问题仍然是:这种(副作用)效果好吗?

首先谈谈原则,副作用通常是危险的,原因有两个:

  • 它们使并发变得更加困难
  • 他们掩盖/隐藏信息

在您的示例中,有一些隐藏的信息。您可以将此称为潜在的副作用,并且可以通过一个问题来暴露它:“这个 doSomethingHere 方法是否创建一个新对象或修改我传入的对象?” 答案很重要,如果它是公共方法,则更是如此。通过阅读 doSomethingHere 方法应该很容易找到答案,特别是如果您保持方法“干净”,但信息仍然被隐藏/模糊。

在这种特定情况下,我会让 doSomethingHere 返回 void。这样人们就不可能认为您创建了一个新对象。这只是个人方法 - 我确信很多开发人员都说您应该返回您修改的对象。或者,您可以选择一个“好的”方法名称。在我看来,“modifyExampleInPlace”或“changeSomeFieldsInPlace”对于您的特定示例来说是非常安全的名称。