Builder subclass pattern with twist in Java
I would like to create an abstract Builder for an abstract class (although it shouldn't be abstract) and each subclass of the abstract class can have its own Builder subclass. I also want every field / attribute to be filled with AKA required. So I am using Builder Patter With Twist ( https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/ ).
I ran into a problem that was solved in this question I asked earlier: Generic parent cannot be returned as child without casting But now I cannot create multiple concrete / subclass collectors.
In the end, I would like to create objects something like this:
ConcreteBuilderA.getBuilder().setValue(Object value).setConcreteValue(int num).build()
If setValue () is owned by AbstractBuilder and others for specificBuilder.
My best shot was (greatly simplified and abstracted):
/**
* @param<B> the type of builded object it should return.
* @param<S> the type of the builder subclass.
* @param<L> the type of the linking interface.
*/
public abstract class AbstractBuilder<B extends AbstractClass, S extends AbstractBuilder, L> implements ValueSetter<L>
{
protected B buildable;
@Override
public L setValue(Object value)
{
//set the value
return this;//<-- returns Object, blocking the use of the ConcreteBuilder methods
}
public abstract B build();
}
|
public class ConcreteBuilder extends AbstractBuilder<ConcreteProduct, ConcreteBuilder, ConcreteValueSetter> implements ConcreteValueSetter
{
@Override
public ConcreteBuilder setConcreteValue(int num)
{
//set value
return this;
}
@Override
public ConcreteProduct build();
{
return buildable;
}
}
|
public interface ValueSetter<L>
{
public L setValue(Object value);
}
|
public interface ConcreteValueSetter
{
public ConcreteBuilder setConcreteValue(int num);
}
As noted, this stops the chaining when it "switches" to the subclass's build methods. I've made several variations of this and I can't seem to get it to work.
So I'm really wondering if this is possible. If so, I would like to see how to do it. If this is not the case, I would like to know some technique that suits my requirements.
Thanks in advance!
source to share
I discovered the answer with the help of Federico Peralta Schaffner. It is likely that I made the developer in my real project difficult. So here is the code for Builder-with-a-twist + inheritance:
/**
*
* @param <P> the type of the product.
* @param <L> the linking interface.
*/
public class AbstractBuilder<P extends AbstractClass, L> implements ValueSetterOne<L>, ValueSetterTwo<L>{
protected P toBeBuild;
@Override
public L setValueTwo(int value) {
//set value
return (L) this;
}
@Override
public ValueSetterTwo<L> setValueOne(int value){
//set value
return this;
}
|
public class ConcreteBuilder extends AbstractBuilder<ConcreteClass, NameSetter> implements NameSetter, Optional{
public static ValueSetter<NameSetter> getBuilder()
{
AbstractBuilder<ConcreteClass, NameSetter> builder = new ConcreteBuilder();
builder.toBeBuild = new ConcreteClass();
return builder;
}
@Override
public Optional buildName(String name) {
this.toBeBuild.setCharacterName(name);
return this;
}
@Override
public ConcreteClass build() {
return this.toBeBuild;
}
@Override
public Optional addExtraObject(Object extra) {
System.out.println("test");
return this;
}
}
|
public interface ValueSetterOne<L> {
public ValueSetterTwo<L> setValueOne(int value);
}
|
public interface ValueSetterTwo<L> {
public L setValue(int value);
}
|
public interface NameSetter {
public Optional buildName(String name);
}
|
public interface Optional {
public ConcreteClass build();
public Optional addExtraObject(Object extra);
}
And then, to test this:
ConcreteBuilder.getBuilder().setValueOne(0).setValueTwo(1).buildName("tricky").addExtraObject(args).build();
source to share