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.
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.