«Пеленальный» сложный неизменный объект - PullRequest
0 голосов
/ 17 января 2019

Это код:

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, который запустит Builder со значениями из существующего объекта A, например:

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

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

В этом случае мне кажется более разумным.

Есть ли еще варианты?

1 Ответ

0 голосов
/ 17 января 2019

Вместо того, чтобы возвращать полностью построенное значение 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, но это не обязательно. Это облегчает возврат ABuilder из createCopyFrom, но это также легко сделать, если методы ABuilder не возвращают this. Вместо этого вы должны установить каждое свойство (например, withProp1, withProp2 и т. Д.), А затем вернуть построитель следующим образом:

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();
    }
}
...