问题
在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)
方法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)
目前的发现
到目前为止,我对该问题的研究使我相信方法 B 对于允许方法链接是有用的,例如vector1 = vector1.rotate(angle).scale(scalar)
,它有它自己的好处,更多的是在事物的可读性方面。
这也让我意识到方法 B 允许您使对象不可变,所以我想推而广之我的问题也是:
什么时候使对象不可变是合适的,尤其是在这个例子中? (一般来说,对于点、 vector 、多边形等。所有这些类型都应该是不可变的吗?)
编辑:
我在创建这篇文章时想到的项目是一个游戏,其中实体由多边形表示,并使用 vector 进行操作。
我相信,由于预期的应用,确保类是线程安全的应该不是问题,因为 Vector 和 Polygon 数据无论如何只能由逻辑线程更改。
这也意味着对于每个实体,这些操作可能每秒执行 60 次(每个游戏刻度)。这是否意味着每次实例化新对象的任何开销都会迅速增加?
最佳答案
通常,您应该更喜欢使对象不可变。您可能想要选择可变对象的原因是:
- 对象有很多状态,因此创建起来很昂贵。例如。想象一个巨大的矩阵。如果不允许突变,则每次都必须复制矩阵,这可能会非常昂贵(例如,请参见
pandas
- 它提供了两种选择)。 - 使其不可变会使 API 非常不直观。这也有点取决于语言的历史。例如,大多数排序库在 e.g. Java 改变集合而不是返回副本。如果您要实现
shuffle
,即使您不担心 (1),最好改变列表,因为如果返回副本会令人惊讶。
一些语言和库提出了第三种方式,其中变异返回一个对象的新“版本”,同时共享以前的状态(参见 this )。这解决了 (1),从而使您可以从不变性中获益,而无需付出大量复制的代价。一些人认为这意味着您实际上应该始终选择不变性,因为随着 (1) 的消失,除了熟悉之外,没有任何理由选择可变性。实际上,有些算法在没有可变状态的情况下很难表达(例如参见 this )。所以我们可能会继续拥有可变状态。
关于Java - 修改对象的内部数据,或使用修改后的数据创建新对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52955601/