我有一个情况需要避免进行防御性拷贝,这种情况下数据可能会被修改,但通常只是读取而不写入。因此,我希望使用不可变对象,并使用函数式的mutator方法来修改它们,这是比较常见的做法(Java Lombok可以在很大程度上自动完成)。我的处理方式如下:
所以,为了获取名称不同的人的副本,我需要调用
public class Person {
private String name, surname;
public Person(String name, String surname) {....}
// getters...
// and instead of setters
public Person withName(String name) {
Person p= copy(); // create a copy of this...
p.name= name;
return p;
}
public Person copy() {....}
}
所以,为了获取名称不同的人的副本,我需要调用
p= new Person("Bar", "Alfred");
...
p= p.withName("Foo");
实际上,这些对象相当大(我最终使用序列化来避免编写复制代码的负担)。
现在,在浏览网页时,我发现了这个实现中潜在的并发问题,因为我的字段不是final的,因此,并发访问可能会看到返回的副本,例如,没有新名称更改(因为在此上下文中不存在操作顺序的保证)。
当然,我不能使我的字段final,因为我首先要进行复制,然后再更改复制品中的数据。
所以,我正在寻找一个好的解决方案来解决这个问题。
我可以使用volatile,但我觉得这不是一个好的解决方案。
另一个解决方案是使用建造者模式:
class PersonBuilder {
String name, surname; ....
}
public class Person {
private final String name, surname;
public Person(PersonBuilder builder) {...}
private PersonBuilder getBuilder() {
return new PersonBuilder(name, surname);
}
public Person withName(String name) {
PersonBuilder b= getBuilder();
b.setName(name);
return new Person(b);
}
}
这里有问题吗?最重要的是,有没有更优雅的方法来完成相同的事情?