3

I would like to create an abstract Builder for an abstract class (although it does not need to be abstract) and every subclass of the abstract class could have its own subclass Builder. I also want every field/attribute to be filled AKA mandatory. So I use the Builder Patter With a Twist (https://blog.jayway.com/2012/02/07/builder-pattern-with-a-twist/).

I encountered a problem which was solved in this question I asked earlier: Generic parent object cannot be returned as child without cast But now I am unable to make multiple concrete/subclass Builders.

In the end I would like to instantiate objects something like this:

ConcreteBuilderA.getBuilder().setValue(Object value).setConcreteValue(int num).build()

Where setValue() belongs to the AbstractBuilder and the others to the concreteBuilder.

My best shot was (heavily 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 marked, this stops the chain when 'switching' to the subclass build methods. I have made some variants to this and I cannot get it to work.

So I am really wondering if this is even possible. If it is, I would like to see how. If it isn't I would like know some technique that does meet my requirements.

Thanks in advance!

RabbitBones22
  • 302
  • 4
  • 16
  • 1
    Hi! Try this: `public abstract class AbstractBuilder> implements ValueSetter` and in `setValue` cast `this` to `L`. Anyway, I find this too complex. Are you sure it's worth the effort? I like Bloch's approach to require mandatory fields in the builder constructor instead of having setter interfaces. With the setter interfaces, you end up swirling around the generic type parameters... – fps Jun 13 '17 at 18:09
  • 1
    I think that in `ConcreteBuilder` you have accidentally switched the first and second generic type parameters. It should be `public class ConcreteBuilder extends AbstractBuilder`, shouldn't it be? By the way, what is `LinkingInterface`? Please also show its code. – fps Jun 13 '17 at 18:15
  • I would like to use the Builders constructor, but in the real project the abstract object already has more than 4 attributes, which are all mandatory... and the concrete wel... a lot more. And putting all those parameters in would violate the SIG Maintainable Code rule that every unit should not have more than 4 parameters. – RabbitBones22 Jun 14 '17 at 07:50

2 Answers2

1

I discovered the answer with the with the help of Federico Peralta Schaffner. It is likely that I made the builder in my real project to complicated. So here is the code for a 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 it: ConcreteBuilder.getBuilder().setValueOne(0).setValueTwo(1).buildName("tricky").addExtraObject(args).build();

RabbitBones22
  • 302
  • 4
  • 16
1

Your problem is a symptom of lazy programming technique. Try this; pretend that you are a professional software developer:

ConcreteBuilderA builder = ConcreteBuilderA.getBuilder();
ThingBeingBuilt thing;

builder.setValue(value);
builder.setConcreteValue(num);
thing = builder.build()
DwB
  • 37,124
  • 11
  • 56
  • 82
  • I am not sure of what you are trying to convey. Do you mean I should not put constraints (the mandatory fields) on the builder and just use it? – RabbitBones22 Jun 14 '17 at 17:01
  • There is no need to return the builder from the setXxxx methods. If you don't depend on this (bad) technique, then it does not matter where the setValue and setConcreteValue methods are implemented. My point is this: chain calling is a lazy technique that is favored by shitty developers. Let go of that technique and your design is fine. – DwB Jun 14 '17 at 17:04
  • Okay... But why is it 'bad' then? I guess I misunderstood the builder pattern. It is meant for building multiple objects that are the same right? And not for actually building complex objects? – RabbitBones22 Jun 14 '17 at 17:14
  • 1
    Builder is for building complex objects. Chain calling is a symptom of lazy programming. – DwB Jun 14 '17 at 17:57
  • What does lazy programmin mean exactly than? – RabbitBones22 Jun 14 '17 at 18:01
  • Okay I see how it is harder to read because of all the different interfaces. But other than that, I do not see any downside or argument against the pattern. So what is the deal? – RabbitBones22 Jun 14 '17 at 18:54
  • Because my program is not meant to use as a library, the final implementation does not have chain calling anymore. I would still like a good explanation why it is not good in general. – RabbitBones22 Jul 03 '17 at 12:32