I'm new to the art of designing fluent, extensible interfaces. I have a chain of builder classes that implement interfaces and both the interfaces and the builder implementations take self-referential type parameters.
Note: This is related to my previous question in which I had attempted to design the interfaces slightly differently before trying this approach in which the interfaces take a self-referential type parameter as well:
Here is the interface:
public interface ILoadableBuilder<C extends ILoadable,T extends ILoadableBean, B extends ILoadableBuilder<C,T,B>> {
T getState();
B setComponentClass(final Class<C> componentClass);
B setDriver(final WebDriver driver);
B setLoadTimeoutInSeconds(final @Nonnegative int loadTimeoutInSeconds);
B setEnumerator(final IEnumeratorBean<? extends IEnumerable<?>,?> enumerator);
}
Here is an implementation, which also takes a self-referential type parameter. The reason the class implementation takes the parameter is that I want it to be extensible so that other builders can then extend this class and inherit all its behavior, and that the setters can be called in any order and the return type will be correct:
public class LoadableBuilder<C extends ILoadable,T extends ILoadableBean,B extends ILoadableBuilder<C,T,B>> implements
ILoadableBuilder<C,T,B> {
private final T componentBean;
private IEnumeratorBean<? extends IEnumerable<?>,?> enumerator;
private Class<C> componentClass;
public LoadableBuilder(final T componentBean) {
this.componentBean = componentBean;
}
public final T getState() {
return componentBean;
}
public final B setComponentClass(final Class<C> componentClass) {
this.componentClass = componentClass;
return (B)this;
}
public final B setDriver(final WebDriver driver) {
getState().setDriver(driver);
return (B)this;
}
public final B setLoadTimeoutInSeconds(final int loadTimeoutInSeconds) {
getState().getLoadTimeoutInSeconds();
return (B)this;
}
public B setEnumerator(final IEnumeratorBean<? extends IEnumerable<?>,?> enumerator) {
this.enumerator = enumerator;
return (B)this;
}
}
My question is, how the heck do you instantiate an instance of this implementation without having to pass a type parameter to the client class? Say, I want to declare a member variable in a class that uses the builder like so:
public ClientClass<C,T> {
private ILoadableBuilder<C,T,_what do I put here????_> builder = new LoadableBuilder<C,T,_what do I put here?????_>();
}
For a method, it's no big deal because I can do this:
public <B extends ILoadableBuilder<C,T,B>> void useABuilder() {
ILoadableBuilder<C,T,B> builder = new LoadableBuilder<C,T,B>();
}
EDIT:
ClientClass would want to build an object that implements the ILoadable interface. I have lots of builders that extend ILoadableBuilder to build objects that implement interfaces which are sub-types of ILoadable. The idea is that I want to be able to get a builder for any object in the inheritance hierarchy underneath ILoadable, which themselves are extensible where necessary.