【问题标题】:Immutable object with side effect具有副作用的不可变对象
【发布时间】:2017-08-11 09:41:26
【问题描述】:

让我们考虑不可变对象File,它封装了指向磁盘上文件的fileName。该对象具有rename 方法,显然是为磁盘上的文件分配新名称。

public final class File {

   private final String fileName;

   public File(String fileName fileName) {
       this.fileName = fileName;
   }

   public File rename(String newName) {
        // Rename the actual file on the disk (code is omitted)
        // and that is the side effect!
        return new File(newName);
   }
}

所以问题是:

  • 如何处理不可变对象的副作用?我们的File 对象一旦创建就应该始终以相同的封装状态工作。并返回具有修改状态的新对象。这在java.lang.String 类中完美完成。但是旧对象(仍然指向错误 fileName)并不好。我们无法使用它,因为状态已损坏。
  • 这是否意味着对象不是真正不可变的?如果我们只想使用具有一致状态的真正不可变对象怎么办?我们不应该重命名磁盘上的文件吗?但是当我们真正需要重命名文件时如何完成工作呢?

假设File 只是一个例子。

【问题讨论】:

  • 由于不能销毁对象,所以只需要等到旧对象符合被GarbageCollected的条件即可
  • 为什么您认为旧文件名是“错误”?它与重命名之前一样有效。只是它指向的文件(文件系统中的一个对象)不存在......
  • @UsagiMiyamoto 因为我不能重用那个特定的对象。它是具有副作用的修改状态。更糟糕的是:旧的File 的所有属性都保持不变,因为对象是不可变的。所以整个对象都坏了。但我明白你的意思。从技术上讲 - 是的。对象仍然是可管理的,但没有用。它仍然与创建时不同。那么它真的是不可变的吗?
  • 当然可以重复使用。 File 代表文件名称,而不是文件,而且文件名不必存在。
  • 对。但那是不可能的。鉴于场景和要求,您不能使这些对象 100% 不可变。您仍然可以努力使状态尽可能不可变,但仅此而已。

标签: java oop immutability


【解决方案1】:

如何处理不可变对象的副作用?我们的 File 对象一旦创建就应该始终以相同的封装状态工作。并返回具有修改状态的新对象。这在 java.lang.String 类中完美完成。但是旧对象(仍然指向错误的文件名)并不好。我们无法使用它,因为状态已损坏。

您的示例有一个问题,无法克服。您的副作用,这部分代码,不在您的控制范围内:

    // Rename the actual file on the disk (code is omitted)
    // and that is the side effect!

对于String,您可以控制字符串的每个字节,因此您可以保证String上方法的纯度。对于您的文件示例,还涉及一个环境 - 操作系统,该文件是否存在。即使它存在,您的进程也可能无法访问它。您实际上无法重命名文件的原因可能有很多。

IMO 无法克服这一点。你周围的世界并不纯粹——你的代码在具有很多副作用和可变性的系统上执行。您的磁盘是有状态的,您的 RAM 不是恒定的。即使在 Haskell 中,来自 https://hackage.haskell.org/package/directory-1.3.1.1/docs/System-Directory.html 的函数 renameFile :: FilePath -> FilePath -> IO () 也不是理想的纯函数 - 在某些情况下它可能会导致错误。

但这不是认为对象无效的理由。正如在 cmets 中已经说过的那样,您封装了文件名,而不是文件描述符。因此,您的 File 代表有效的文件名。可能问题更多的是关于重命名方法的有效性?

这是否意味着对象不是真正不可变的?如果我们只想使用具有一致状态的真正不可变对象怎么办?我们不应该重命名磁盘上的文件吗?但是当我们真正需要重命名文件时如何完成工作呢?

它是不可变的。对这个对象的调用rename 不是纯粹的,仅此而已。 不变性纯度是不同的术语。您的对象可能是不可变的,并且仍然有副作用,就像您的示例一样。

【讨论】:

  • 我不知道你所说的“纯”是什么意思,但是在Java中“纯”已经有了一个含义:它是“原生”的反义词。
  • 我的意思是我的意思。纳夫说。
【解决方案2】:

我想,你应该阅读下一篇文章:http://www.yegor256.com/2016/09/07/gradients-of-immutability.html 因为不变性不是非黑即白

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-12
    • 1970-01-01
    • 2016-05-02
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多