建造者模式:通过其他建造者创建的嵌套对象

Builder pattern: nested objects created through other builders

假设我有两个对象,都是通过构建器模式创建的,一个嵌套到另一个对象中:

class Parent {
    private final Child child;

    private Parent(Child child) {
         this.child = child;
    }

    public static class Builder {
         private Child child;         

         public Builder() {}

         public Builder child(Child child) {
             this.child = child;
             return this;
         }

         public Parent build() {
             return new Parent(child);
         }
    }
}

class Child {
    private final long id;

    private Child(Builder builder) {
         this.id = builder.id;
    }

    public static class Builder {
         private long id;         

         public Builder() {}

         public Builder id(long id) {
             this.id = id;
             return this;
         }

         public Parent build() {
             return new Child(this);
         }
    }
}

所以,显而易见的用法非常简单:

Person.Builder parentBuilder = new Person.Builder().child(new Child.Builder().id(10).build());

制作

是不是很常见
public static class Builder {
     private ChildBuilder child;         

     public Builder() {}

     public Builder child(ChildBuilder child) {
         this.child = child;
         return this;
     }

     public Builder resetChildId() {
          child.id(0);
          return this;
     }

     public Parent build() {
         Child childToPass = child.build();
         return new Parent(childToPass);
     }
}

这样以后仍然可以更新 child#id,但是由于延迟绑定,最近在 Parent.Builder#build() 方法期间抛出错误。

希望对您有所帮助

关于如何使用它的示例在 main 方法中,这将打印 10 0

parent class:

public class Parent {
  private final Child child;

  private Parent(Child child) {
     this.child = child;
  }

  public Child getChild(){
    return this.child;
  }

  public static class Builder {
    private Child.Builder childBuilder;

    public Builder() {}

    public Builder child(Child.Builder childBuilder) {
      this.childBuilder = childBuilder;
      return this;
    }

    public void resetChildId() {
      childBuilder = childBuilder.id(0);
    }

    public Parent build() {
      return new Parent(childBuilder.build());
    }
  }

  public static void main (String[] args){
    Parent.Builder parentBuilder = new Parent.Builder().child(new Child.Builder().id(10));

    System.out.println(parentBuilder.build().getChild().getId());
    //Reset the sucker
    parentBuilder.resetChildId();
    System.out.println(parentBuilder.build().getChild().getId());
  }
}

child class:

class Child {
  private final long id;

  private Child(Builder builder) {
    this.id = builder.id;
  }

  public long getId(){
    return this.id;
  }

  public static class Builder {
    private long id;

    public Builder() {}

    public Builder id(long id) {
      this.id = id;
      return this;
    }

    public Child build() {
      return new Child(this);
    }
  }
}

我会将 Child 实例传递给 Parent 而不是 ChildBuilder 实例。

如果您希望之后更改 Child 属性,那么您只需从 parentBuilder.child().

构造一个新的 ChildBuilder

但是,当我看到所有这些构建器时,我对设计感到担忧。 DDD 是关于无处不在的语言,"builder" 当然不是它的一部分。有时您别无选择在设计中引入技术概念,但我相信您可能忘记了其他可能有帮助的 DDD 构建块。

I have builders everywhere because I have to do validation for each domain entity in the app. For example name for Parent not longer than 255, but for child not more than 1000. - Tahar Bakir (from the comments)

您上面描述的规则可能会被封装并强制执行在域概念中的构造,例如 ParentNameChildName 可以作为值对象实现。

您的 ParentChild 类 然后可以使用这些概念而不是字符串。