Reputation:
I am trying to implement Builder pattern with inheritance and found the following solution .
This is B
class:
public class B extends A {
public static abstract class Builder<T extends Builder<T>>
extends A.Builder<T> {
@Override
public abstract T getThis();
public Builder Bmethod() {
//implementation
return this;
}
public B build() {
return new B(this);
}
}
private B(Builder builder) {
super(builder);
//B field assignment
}
}
Now I want to make class C also extendable. This is the way I do it:
public class C extends B {
...
public static class Builder<T extends Builder<T>> extends B.Builder<T> {
....
}
}
So, in C
we have builder that can be extended in, for example, D
. My question is what is the right way to create C.Builder instance. I mean, what should I set in its generics:
C.Builder<WHAT HERE> builder = new C.Builder<>();
Upvotes: 4
Views: 1670
Reputation: 8074
Since the argument T
for C.Builder
must be something that extends C.Builder
you must create another class that extends C.Builder
, as you cannot use C.Builder
itself as it is parameterized.
A solution therefore for inherited builders is to create two builders, one which is generic, extensible, protected and abstract, and another one that is public, final and not generic used for the actual building.
Here are sample classes that show this:
public class Person {
private final String name;
public Person(String name) {
this.name = name;
}
public String getName() {
return name;
}
protected static abstract class ExtensiblePersonBuilder<S, T extends Person> {
protected String name;
public S name(String name) {
this.name = name;
return self();
}
public abstract S self();
public abstract T build();
}
public static final class PersonBuilder extends ExtensiblePersonBuilder<PersonBuilder, Person> {
@Override
public PersonBuilder self() {
return this;
}
@Override
public Person build() {
return new Person(name);
}
}
}
And a subclass, with builder:
public class Employee extends Person {
private int number;
public Employee(String name, int number) {
super(name);
this.number = number;
}
protected static abstract class ExtensibleEmployeeBuilder<S, T extends Employee> extends ExtensiblePersonBuilder<S, T> {
protected int number;
public S number(int number) {
this.number = number;
return self();
}
}
public static final class EmployeeBuilder extends ExtensibleEmployeeBuilder<EmployeeBuilder, Employee> {
@Override
public EmployeeBuilder self() {
return this;
}
@Override
public Employee build() {
return new Employee(name, number);
}
}
}
And a sub sub class:
public class Manager extends Employee {
private String teamName;
public Manager(String name, int number, String teamName) {
super(name, number);
this.teamName = teamName;
}
protected static abstract class ExtensibleManagerBuilder<S, T extends Manager> extends ExtensibleEmployeeBuilder<S, T> {
protected String teamName;
public S teamName(String teamName) {
this.teamName = teamName;
return self();
}
}
public static final class ManagerBuilder extends ExtensibleManagerBuilder<ManagerBuilder, Manager> {
@Override
public ManagerBuilder self() {
return this;
}
@Override
public Manager build() {
return new Manager(name, number, teamName);
}
}
}
You can use these builders like this:
Person p = new PersonBuilder().name("John").build();
or:
Manager m = new ManagerBuilder().name("Jeff").teamName("X").number(2).build();
Upvotes: 4