This is related to the following question:
How to improve the builder pattern?
I\'m curious whether it\'s possible to implement a builder with the following
Building on Jordão's idea, I came up with the following, which may arguably satisfy all requirements 1-6 even though there is some duplicate code in the type parameters. Essentially, the idea is to "pass around" the return types of each method by using type parameters to override the return value of the inherited methods. Even though the code is verbose and impractical, and actually requires Omega(n^3) characters if you extend it out to an arbitrary number of fields n, I'm posting it because I think it's an interesting use of the java type system. If anyone can find a way to reduce the number of type parameters (especially asymptotically), please post in the comments or write another answer.
public final class Foo {
public final int a;
public final int b;
public final int c;
private Foo(
int a,
int b,
int c) {
this.a = a;
this.b = b;
this.c = c;
}
public static BuilderA extends BuilderB, ?>, ? extends BuilderC, ?>> newBuilder() {
return new BuilderFinal();
}
public static class BuilderA, C extends BuilderC, ?>> {
private volatile int a;
@SuppressWarnings("unchecked")
public B a(int v) {
a = v;
return (B) this;
}
public int a() {
return a;
}
}
public static class BuilderB, C extends BuilderC, ?>> extends BuilderA {
private volatile int b;
@SuppressWarnings("unchecked")
public C b(int v) {
b = v;
return (C) this;
}
public int b() {
return b;
}
}
public static class BuilderC, C extends BuilderC, ?>> extends BuilderB {
private volatile int c;
@SuppressWarnings("unchecked")
public BuilderFinal c(int v) {
c = v;
return (BuilderFinal) this;
}
public int c() {
return c;
}
}
public static class BuilderFinal extends BuilderC {
public Foo build() {
return new Foo(
a(),
b(),
c());
}
}
public static void main(String[] args) {
Foo f1 = newBuilder().a(1).b(2).c(3).a(2).build();
Foo f2 = newBuilder().a(1).a(2).c(3).build(); // compile error
Foo f3 = newBuilder().a(1).b(2).a(3).b(4).b(5).build(); // compile error
}
}