java - 避免输出参数(没有副作用)

标签 java coding-style parameter-passing side-effects

我正在阅读 Robert C. Martin 的“干净代码”,但我无法完全理解第 44 到 45 页上的“没有副作用”和“输出参数”部分。

在“无副作用”部分中指出,传递给方法参数的更改被视为副作用,不应进行。

在“输出参数”部分,声明方法的参数不应改变。如果必须更改某些状态,则方法应该仅更改其拥有对象的状态。

我确实理解,如果指定此行为的方法是由不完全了解这一点的客户端调用的,则副作用和输出参数可能会导致令人困惑的行为和错误。此外,这在多线程环境中工作时也是有问题的。

但是,关于“干净的代码”这本书是基于 Java 示例编写的,我感到很困惑。

让我们看一个例子。
假设我们有一个玩家类:

public class Player {
    private int healthPoints;
    private boolean alive = true;

    public Player(int healthPoints) {
        if(healthPoints < 1) {
            throw new IllegalArgumentException();
        }
        this.healthPoints = healthPoints;
    }

    public boolean isAlive() {
        return this.alive;
    }

    public void fight(Player otherPlayer) {
        //do some fighting which will change this instance
        // but also the otherPlayer instance
    }
}

如果我们现在调用以下函数:
player1.fight(player2);

这将改变 player1 的状态和 player2 的状态。
在大多数情况下,Robert C. Martin 不鼓励这样做。但实际上,我经常看到这种模式。大多数 Java 程序真正涉及突变,并且对象在它们被创建的范围之外被改变。

如果我们创建一场改变双方玩家的战斗,情况会更糟,因为现在另一个对象在其方法中改变了两个参数:
battle.fight(player1, player2)

我在这里想念什么吗?什么时候可以在方法中(在 Java 中)改变参数?前段时间我问了一个非常相似的问题( Is mutating object-parameters in a method(in Java) a bad practice? )。

最佳答案

归根结底,这些规则的存在是为了通过消除意外行为来使程序员的生活更轻松。它们帮助人类推理程序。因此,关键是确保您可以查看一行代码并了解它的作用。

如果我,作为一个程序员,看到这一行:

player1.fight(player2);

我希望两者都是 player1player2以某种方式发生变异。这也适用于 Arrays.sort(array); ,它是语言的一部分。

但是,如果在您的 isAlive()函数,你执行了一些突变(可能杀死健康低于零的玩家),在我看来,这是不好的做法,因为作为程序员,我期待一个名为 isFoo() 的函数。或 getFoo()简单地返回有关对象的数据而没有任何变化。

归根结底,当您在一年后回来查看您的代码时,这些指南将使您的生活更轻松,因此,如果您有疑问,请问问自己您对具有相同签名的方法有何期望做什么(即我期望 public void setAge(int age); 做什么?它是否按照我的期望做?)

附言

某些语言(例如 Haskell)根本不允许任何突变。排除 IO 和随机性,函数影响程序的唯一方式是通过它的返回值。如果您想了解如何完成“无副作用的编程”,值得一试。

关于java - 避免输出参数(没有副作用),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59801071/

相关文章:

c - 如何将数组传递给这样的函数 : void fooboo(char array[i]);

c++ - 使用自动推导的 lambda 参数作为常量表达式

java - 如何将数组元素从子类传递到主类

java - 在 OAuth 2.0 安全 Web 应用程序上使用 JMeter 脚本进行性能测试

C++源码组织-COM口初始化

java - 使用 { } 分割大块代码以提高代码可读性 - 好的做法?

java - 使用 if 和 while 接受数组中的元素

java - 为什么在 java 泛型中 List<Integer> 是 List< 的子类型?扩展整数>?

coding-style - 一个文件的最大行数?

c - 如何将指向数组的指针传递给函数?