2

Let's assume I have two objects, both created through the builder pattern and one is nested into other:

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

So, the obvious usage is quite simple:

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

Is it quite common to make

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

That way it is still possible to update the child#id later, however due to late binding the errors are thrown lately during Parent.Builder#build() method.

Vadim Kirilchuk
  • 3,532
  • 4
  • 32
  • 49
  • 2
    the dp Builder allows you to build an immutable object, you don't modify, hence the final modifiers on the class members. So no modifications are possible once the object is created. Plus the you need to correct public Builder id(long id) { this.id = id; return this;} and public Builder child(Child child) { this.child = child; return this;} – Tahar Bakir Oct 19 '15 at 10:05
  • Yep, correct. But I want to modify nested object in the Builder, the Parent is not fully constructed yet. So, my question is what are possible solutions? Let me correct/rephrase the question. – Vadim Kirilchuk Oct 19 '15 at 10:16
  • 2
    Quite common i don't know, What i can tell you is that in the Parent Builder the child() method takes a Child object, the child object is immutable, you cannot resetChildId later, you need to keep the Child builder, that way you can set the id later and build only when you're sur the state won't change anymore. – Tahar Bakir Oct 19 '15 at 10:38
  • I don't think it is quite common to have inner classes in immutable outer classes in the first place. Every other problem you have is just a consequence of that. If there is a one-to-one relationship between a `Parent` and `Child` instance anyway, why not do away with the `Child` class completely? – biziclop Oct 19 '15 at 10:49
  • Because I simplified example a lot. Actually these are JPA Entities and Child is actually an inner collection of Child, moreover there are also GrandChild. Thanks for the input. – Vadim Kirilchuk Oct 19 '15 at 13:07
  • The class design is too complex. Any implementation will be difficult to test and difficult to maintain. Only a top-level class should require a builder. An inner class that requires a builder is too complex. Refactor the design into smaller, simpler pieces. – jaco0646 Oct 19 '15 at 13:39
  • 1
    @VadimKirilchuk Why don't you simply pass the child instance rather than the builder. If you want to change something of the child you can just replace the whole child instance. If you only want to change a single piece of the child then you may do something like `parent.child(new ChildBuilder(parent.child()).setSomeProperty(...).build())` – plalx Oct 19 '15 at 13:45
  • @jaco0646 I see your point. 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. I can validate on Controller level, but in DDD it's a responsibility of domain.I know that there is validation api and also hibernate-validators exist, but we decided to go with builders. – Vadim Kirilchuk Oct 19 '15 at 14:00
  • @plalx didn't get your example. The Child entity does have a ChildBuilder, thus Child doesn't have any setters (or they are all private - this is how Builder pattern works), so the Child is immutable once it is built. – Vadim Kirilchuk Oct 19 '15 at 14:03
  • 1
    @VadimKirilchuk This is what I'm saying, allow constructing a builder from an existing child. Therefore, if you want to change child properties you may replace the entire child instance by constructing a `ChildBuilder` from an existing child. `ParentBuilder` will hold `Child` instances rather than `ChildBuilder` instances. – plalx Oct 19 '15 at 14:18
  • 1
    @VadimKirilchuk [By the way, I wouldn't care about nice and clean error reporting to the UI. That's a UX problem which can be solved in the UI.](http://stackoverflow.com/questions/28395176/should-i-abstract-the-validation-framework-from-domain-layer/28397201#28397201) Also, you may not need all those builders at all if you make proper use of value objects. For instance, you may have a `ParentName` class that enforces the 255 characters rule. Your `Parent` object can then expect a `ParentName` than a simple string. – plalx Oct 19 '15 at 14:23
  • @plalx Got it, makes sense. I already have ChildBuilder(Child source) constructor, you may post it as an answer. Re UI: validation is done on UI too, but validation should be in both places, backend can't rely on frontend here. – Vadim Kirilchuk Oct 20 '15 at 08:22
  • 1
    Yes, you must perform server-side validation too. What I'm saying is that duplicating some of the validation rules on the client to provide a better UX experience is not really duplication since it serves a different purpose. On the UI I would use validation frameworks to express validation rules and server-side I would rely on DDD building blocks, such as value objects. – plalx Oct 20 '15 at 12:24

2 Answers2

2

I would pass a Child instance to Parent rather than a ChildBuilder instance.

If you wish to change Child properties afterwards then you can simply construct a new ChildBuilder from parentBuilder.child().

However, I'm concerned about the design when I see all those builders. DDD is all about the ubiquitous language and "builder" is certainly not part of it. Sometimes you have no choice to introduce technical concepts in the design, but I believe that you may be forgetting about other DDD building blocks that may help.

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)

The rules you describe above may be encapsulated and enforce upon construction in domain concepts such as ParentName and ChildName that can be implemented as value objects.

Your Parent and Child classes can then work with those concepts rather than strings.

plalx
  • 42,889
  • 6
  • 74
  • 90
  • Could you please give me some useful links to articles with explanation and examples where validation in done in value objects? Thanks – Vadim Kirilchuk Oct 20 '15 at 12:45
1

Hope this helps

the example on how to use it is in the main method, this will print 10 0

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

The 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);
    }
  }
}
Tahar Bakir
  • 716
  • 5
  • 14
  • Yep, it's exactly the code I concerned about. In the code you build the Child only on call to parent#build() which delays all the validation. So, my question is to know how do other people usually do? Is it ok to have late validation or is it better to go with completely different approach? – Vadim Kirilchuk Oct 19 '15 at 13:10