【问题标题】:"Changing" complex immutable object“改变”复杂的不可变对象
【发布时间】:2019-01-17 10:29:48
【问题描述】:

这是代码:

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),它是使用 Builder 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();
}

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

还有比这更多的选择吗?

【问题讨论】:

  • 肮脏的方法是使用clone(),然后将prop2更改为新值
  • 我不会把使用克隆称为脏,而是说做这种事情的首选方式。如果您有更复杂的具有关系的对象,则必须小心,但克隆可以正常工作。事实上,查看不可变请求/响应对象的一些 psr7 实现。我见过的所有使用克隆。

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


【解决方案1】:

除了从changeProp2 返回完全构造的A 值,您还可以创建一个方法,例如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)
    }
}

需要注意的一些重要事项:在上面的示例中,我使用fluent interface 代替ABuilder,但这不是必需的。它使从createCopyFrom 返回ABuilder 变得更容易,但如果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();
    }
}

【讨论】:

  • 谢谢。似乎您的解决方案类似于我的选项2。您只需在 createCopyFrom 中创建构建器,然后我使用 new ABuilder(this) 创建它(在这种情况下,我将对象 A 传递给 ABuilder 以使用 A 类的当前状态初始化 ABuilder)。
猜你喜欢
  • 1970-01-01
  • 2011-11-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-08-18
相关资源
最近更新 更多