Java - 修改对象的内部数据,或使用修改后的数据创建新对象

标签 java oop immutability

问题

在Java中,根据标准的代码风格和设计原则,什么时候修改一个对象的内部数据比较合适,什么时候使用修改后的数据创建一个新的对象比较合适?

例如,假设我有一些类 Vector2D,它包含一个 x 分量和一个 y 分量,我想旋转该 vector :

方法A

public class Vector2D{
    private int x;
    private int y;
    public Vector2D(int x, int y){
        this.x = x;
        this.y = y;
    }
    public void rotate(double angle){
        //code for finding rotated vector
        x = rotated_x;
        y = rotated_y;
    }
}

然后可以使用 vector1.rotate(angle)

旋转 Vector2D 对象

方法B

public class Vector2D{
    private final int x;
    private final int y;
    public Vector2D(int x, int y){
        this.x = x;
        this.y = y;
    }
    public Vector2D rotate(double angle){
        //code for finding rotated vector
        Vector2D rotated = new Vector2D(rotated_x, rotated_y);
        return(rotated);
    }
}

然后可以使用 vector1 = vector1.rotate(angle)

旋转 Vector2D 对象

目前的发现

到目前为止,我对该问题的研究使我相信方法 B 对于允许方法链接是有用的,例如vector1 = vector1.rotate(angle).scale(scalar),它有它自己的好处,更多的是在事物的可读性方面。

这也让我意识到方法 B 允许您使对象不可变,所以我想推而广之我的问题也是:

什么时候使对象不可变是合适的,尤其是在这个例子中? (一般来说,对于点、 vector 、多边形等。所有这些类型都应该是不可变的吗?)

编辑:

我在创建这篇文章时想到的项目是一个游戏,其中实体由多边形表示,并使用 vector 进行操作。

我相信,由于预期的应用,确保类是线程安全的应该不是问题,因为 Vector 和 Polygon 数据无论如何只能由逻辑线程更改。

这也意味着对于每个实体,这些操作可能每秒执行 60 次(每个游戏刻度)。这是否意味着每次实例化新对象的任何开销都会迅速增加?

最佳答案

通常,您应该更喜欢使对象不可变。您可能想要选择可变对象的原因是:

  1. 对象有很多状态,因此创建起来很昂贵。例如。想象一个巨大的矩阵。如果不允许突变,则每次都必须复制矩阵,这可能会非常昂贵(例如,请参见 pandas - 它提供了两种选择)。
  2. 使其不可变会使 API 非常不直观。这也有点取决于语言的历史。例如,大多数排序库在 e.g. Java 改变集合而不是返回副本。如果您要实现 shuffle,即使您不担心 (1),最好改变列表,因为如果返回副本会令人惊讶。

一些语言和库提出了第三种方式,其中变异返回一个对象的新“版本”,同时共享以前的状态(参见 this )。这解决了 (1),从而使您可以从不变性中获益,而无需付出大量复制的代价。一些人认为这意味着您实际上应该始终选择不变性,因为随着 (1) 的消失,除了熟悉之外,没有任何理由选择可变性。实际上,有些算法在没有可变状态的情况下很难表达(例如参见 this )。所以我们可能会继续拥有可变状态。

关于Java - 修改对象的内部数据,或使用修改后的数据创建新对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52955601/

相关文章:

hash - 创建一个在模块外部只读但在内部读/写的哈希

java - 在STS中部署外部项目的资源

java - 使用后关闭所有套接字?在服务器端

java - 如何获取变量的字段名?

java - 可变对象的安全发布

java - 从 javabean 创建不可变对象(immutable对象)

java - 一个 21 字节的 UTF-8 序列如何来自 5 个字符?

java - 公共(public)构造函数,不能创建实例

javascript - 您可以将对象类型设置为自定义名称而不是 Javascript 中的函数吗

oop - 对象间的CBO耦合