In general, it is very simple to implement in Java the builder pattern, a few lines of code and the problem is solved but, when we are using inheritance, it is not as intuitive apparently as it should be. I have lately seen poor attempts of doing it and not achieving the desired result.
In this article, we are going to build a very simple example of that.
public class Parent {
private final String a;
protected Parent(final Builder<?> builder) {
this.a = builder.a;
}
public String getA() { return a; }
public static class Builder<T extends Builder<T>> {
private String a;
public T a(final String a) {
this.a = a;
return (T) this;
}
public Parent build() {
return new Parent(this);
}
}
}
In this first class, the parent class, we can see we are using generics to allow child classes to pass their builders.
public class Children extends Parent {
private final String b;
protected Children(final Builder builder) {
super(builder);
this.b = builder.b;
}
public String getB() {
return b;
}
public static Builder builder() {
return new Builder();
}
public static class Builder extends Parent.Builder<Builder> {
private String b;
public Builder b(final String b) {
this.b = b;
return this;
}
public Children build() {
return new Children(this);
}
}
}
Here, we can see how we pass the child builder in the diamond operator, this will allow us to add values for the properties to the patent and to the child using the builder.
public class Main {
public static void main(String[] args) {
final Children children = Children.builder()
.a("Hi")
.b("Bye")
.build();
System.out.println(children.toString());
}
}
Here, we can see how to use the builder. Thanks to the generics, the call to .a(“Hi”) returns a child builder and not a parent builder what it would make impossible to call .b(“Bye”).
I hope it is useful.