Two approaches : StepBuilder pattern, mentioned here (thanks to Eritrean) and a custom one, described after.
StepBuilder
Inside your builder class, define as many interfaces as "steps" your building should have. The returning type of a method in an interface returns to the type where the next methods should be available.
Here b() can only be called after a().
public class Builder {
/*
* next available methods are defined by
* the returned interface type
*/
private static interface AStep {
BStep a();
}
private static interface BStep {
void b();
}
private static class Steps implements AStep, BStep {
BStep a() {
//
return this;
}
void b() {
//
return this;
}
}
}
Custom approach with Abstract class (I call it : the AbstractBuilder)
As I couldn't define same methods names with the StepBuilder approach I tried something else.
I defined a main Builder with the first callable methods (visible), common methods and the build() method (protected, because it will only be availble through other classes if needed).
I defined an abstract class, called AbstractBuilder, with an attribute of Builder type and a constructor setting this attribute.
I defined as many builders as steps I have. All those builders extends AbstractBuilder and thus have common methods and ending method available if needed, by calling it on the Builder instance.
It looks like this :
public class AbstractBuilder {
protected Builder builder;
protected AbstractBuilder(Builder builder) {
this.builder = builder;
}
}
public class Builder {
public BStep a() {
//
return new BStep(this);
}
protected Object build() {
//
return null;
}
}
public class BStep extends AbstractBuilder {
protected BStep(Builder builder) {
super(builder);
}
public CStep b() {
//
return new CStep(builder);
}
public Object build() {
return builder.build();
}
}
public class CStep extends AbstractBuilder {
protected CStep(Builder builder) {
super(builder);
}
public BStep and() {
//
return new BStep(builder);
}
public DStep c() {
//
return new DStep(builder);
}
public Object build() {
return builder.build();
}
}
public class DStep extends AbstractBuilder {
protected DStep(Builder builder) {
super(builder);
}
public CStep and() {
//
return new CStep(builder);
}
public EStep d() {
// etc. ... return new EStep(builder);
}
public Object build() {
return builder.build();
}
}
with this pattern you can manage the availability of methods after each calls and use "backwards" loops :
Builder builder = new Builder();
builder.a().b().and().a().b().c().and().b().build();