“改变”复杂的不可变对象

时间:2019-01-17 10:29:48

标签: java design-patterns domain-driven-design builder

这是代码:

class A{
prop1, prop2, prop3, prop4, ...

 private A(ABuilder b){
   this.prop1 = b.prop1;
   ...
 }

 A changeProp2(){
   //easiest way to return new immutable A?
 }

 class ABuilder{
   withProp1()
   withProp2()
   withProp3()
   ...
   build()
 }

}


A a = new ABuilder().withProp1().withProp2().build();
A newA = a.changeProp2();

我有一个不变的对象(在这种情况下为A),该对象是使用生成器ABuilder构造的。现在,当我想从现有的复杂A对象中新建A对象时,就我而言,可以调用方法changeProp2()。此方法应复制对象a的所有内部属性,仅将property2更改为新值,然后返回新对象newA

最好的方法是什么?

我到目前为止发现的选项是:

changeProp2()方法内部,我可以复制所有属性-但这似乎太多了,并且如果将来有changeProp3()方法,也无法重用。

//option1
A changeProp2(){
  return new ABuilder().withProp1(this.prop1).withProp2("newProp2")....build();
}

将复制构造函数添加到Builder中,它将使用现有对象A中的值来初始化Builder,如下所示:

//option2
class ABuilder{
  ABuilder(A a){
    this.prop1 = a.prop1;
    ...
  }
}

A changeProp2(){
  return new ABuilder(this).withProp2("newProp2").build();
}

在这种情况下,这对我来说似乎更合理。

还有更多选择吗?

1 个答案:

答案 0 :(得分:1)

您可以创建诸如A之类的方法来返回changeProp2的构建器,而不是从createCopyFrom返回一个完整的A值。例如:

public class A {

    private final String prop1;
    private final String prop2;
    private final String prop3;

    public A(String prop1, String prop2, String prop3) {
        this.prop1 = prop1;
        this.prop2 = prop2;
        this.prop3 = prop3;
    }

    public ABuilder createCopyFrom() {
        return new ABuilder()
            .withProp1(prop1)
            .withProp2(prop2)
            .withProp3(prop3);
    }

    // ...getters...
}

public class ABuilder {

    private String prop1;
    private String prop2;
    private String prop3;

    public ABuilder withProp1(String prop1) {
        this.prop1 = prop1;
        return this;
    }

    public ABuilder withProp2(String prop2) {
        this.prop2 = prop2;
        return this;
    }

    public ABuilder withProp3(String prop3) {
        this.prop3 = prop3;
        return this;
    }

    public A build() {
        return new A(prop1, prop2, prop3)
    }
}

一些重要的注意事项:在上面的示例中,我对ABuilder使用了fluent interface,但这不是必需的。它使从ABuilder返回createCopyFrom更加容易,但是如果ABuilder方法不返回this,也可以轻松完成。相反,您将设置每个属性(例如withProp1withProp2等),然后按以下方式返回构建器:

public ABuilder createCopyFrom() {
    ABuilder builder = new ABuilder();
    builder.withProp1(prop1)
    builder.withProp2(prop2)
    builder.withProp3(prop3);
    return builder;
}

此外,如果您想使用诸如changeProp2之类的方法,则可以利用createCopyFrom方法来仅更改感兴趣的属性:

public class A {

    // ...same methods and fields as before...

    public A changeProp2(String prop2) {
        return createCopyFrom().withProp2(prop2).build();
    }
}