我有一个关于如何避免对Java对象产生副作用的问题。 我们假设我有一个 MyObject 类的实例 myObject 。我想通过一系列方法/命令处理 myobject ,并且在每个命令级别,我想用方法/命令计算的内容来丰富 myObject 。
此处 myObject 的类是以下的实例:
public class MyObject {
private int resultOfCommand1;
private int resultOfCommand2;
private int resultOfCommand3;
private int resultOfCommand4;
....
....
}
以下是必须通过以下方式处理 myObject 的方法/命令:
private MyObject command1(MyObject myObject) {
return myObject.setRresultOfCommand1(1);
}
private MyObject command2(MyObject myObject) {
return myObject.setRresultOfCommand2(2);
}
private MyObject command3(MyObject myObject) {
return myObject.setRresultOfCommand3(3);
}
private MyObject command4(MyObject myObject) {
return myObject.setRresultOfCommand4(4);
}
所以上面显示的设计确实有副作用,我想避免这样的事情。
有人能告诉我避免副作用的最佳方法吗?是否更好地总是复制作为参数传递的对象(在本例中为myObject),对副本进行更改然后返回它? 有没有最好的方法来保证多线程安全?
任何帮助将不胜感激。 贺
答案 0 :(得分:2)
如果要避免副作用,设置值的方法不得更改实例,而是返回新实例(副本)。在该方法中,您使用构造函数来设置所有(最终)值。
示例:
class C {
private final int x;
private final int y;
public C(int _x) {
super();
this.x = _x;
this.y = -1;
}
public C(int _x, int _y) {
super();
this.x = _x;
this.y = _y;
}
public C setY(int _y) {
return new C(this.x, _y);
}
}
要防止副作用,只需将字段声明为final
即可。如果所有字段都是final
,则值(在基本类型的情况下)和对象引用是不可变的。在对象引用的情况下,该对象也必须是不可变的,以实现“完全不变”。
所以你不要改变副本,但你构造一个带有新值的副本。
现在传递不可变实例是安全的;它不能改变,所以它是线程安全的。