Subclassing a Java Builder Class

Subclassing a Java Builder class

You can solve it using generics. I think this is called the "Curiously recurring generic patterns"

Make the return type of the base class builder methods a generic argument.

public class NutritionFacts {

private final int calories;

public static class Builder<T extends Builder<T>> {

private int calories = 0;

public Builder() {}

public T calories(int val) {
calories = val;
return (T) this;
}

public NutritionFacts build() { return new NutritionFacts(this); }
}

protected NutritionFacts(Builder<?> builder) {
calories = builder.calories;
}
}

Now instantiate the base builder with the derived class builder as the generic argument.

public class GMOFacts extends NutritionFacts {

private final boolean hasGMO;

public static class Builder extends NutritionFacts.Builder<Builder> {

private boolean hasGMO = false;

public Builder() {}

public Builder GMO(boolean val) {
hasGMO = val;
return this;
}

public GMOFacts build() { return new GMOFacts(this); }
}

protected GMOFacts(Builder builder) {
super(builder);
hasGMO = builder.hasGMO;
}
}

How to subclass a Java builder class?

Create a super class for the payloads only if the mentioned fields are not common by a coincidence. You can move common fields and methods (but not the builders) in there. You could even create a super class for the builders but it will probably clutter the code too much.

If you really have a use for the payload super class then you can implement your execute method with the Visitor Pattern:

First, you have to create a visitor where you can access your concrete classes:

public class PayloadVisitor {

public void visit(PayloadA payloadA) {
// use payload A here
}

public void visit(PayloadB payloadB) {
// use payload B here
}
}

Then you have to add a method to your super class accepting the visitor:

public abstract class Payload {

// common fields and methods

public abstract void accept(PayloadVisitor visitor);
}

Override the method accept in the subclasses:

public final class PayloadA extends Payload {

// ...

@Override
public void accept(PayloadVisitor visitor) {
visitor.visit(this);
}
}

public final class PayloadB extends Payload {

// ...

@Override
public void accept(PayloadVisitor visitor) {
visitor.visit(this);
}
}

Your method execute just redirects the call to the according visit method:

private void execute(Payload payload) {
payload.accept(new PayloadVisitor());
}

The visitor pattern can be overwhelming. You can also keep it simple and use instanceof to determine the concrete class.

Builder Pattern and Inheritance

This is certainly possible with the recursive bound, but the subtype builders need to also be generic, and you need a few interim abstract classes. It's a little bit cumbersome, but it's still easier than the non-generic version.

/**
* Extend this for Mammal subtype builders.
*/
abstract class GenericMammalBuilder<B extends GenericMammalBuilder<B>> {
String sex;
String name;

B sex(String sex) {
this.sex = sex;
return self();
}

B name(String name) {
this.name = name;
return self();
}

abstract Mammal build();

@SuppressWarnings("unchecked")
final B self() {
return (B) this;
}
}

/**
* Use this to actually build new Mammal instances.
*/
final class MammalBuilder extends GenericMammalBuilder<MammalBuilder> {
@Override
Mammal build() {
return new Mammal(this);
}
}

/**
* Extend this for Rabbit subtype builders, e.g. LopBuilder.
*/
abstract class GenericRabbitBuilder<B extends GenericRabbitBuilder<B>>
extends GenericMammalBuilder<B> {
Color furColor;

B furColor(Color furColor) {
this.furColor = furColor;
return self();
}

@Override
abstract Rabbit build();
}

/**
* Use this to actually build new Rabbit instances.
*/
final class RabbitBuilder extends GenericRabbitBuilder<RabbitBuilder> {
@Override
Rabbit build() {
return new Rabbit(this);
}
}

There's a way to avoid having the "concrete" leaf classes, where if we had this:

class MammalBuilder<B extends MammalBuilder<B>> {
...
}
class RabbitBuilder<B extends RabbitBuilder<B>>
extends MammalBuilder<B> {
...
}

Then you need to create new instances with a diamond, and use wildcards in the reference type:

static RabbitBuilder<?> builder() {
return new RabbitBuilder<>();
}

That works because the bound on the type variable ensures that all the methods of e.g. RabbitBuilder have a return type with RabbitBuilder, even when the type argument is just a wildcard.

I'm not much of a fan of that, though, because you need to use wildcards everywhere, and you can only create a new instance using the diamond or a raw type. I suppose you end up with a little awkwardness either way.


And by the way, about this:

@SuppressWarnings("unchecked")
final B self() {
return (B) this;
}

There's a way to avoid that unchecked cast, which is to make the method abstract:

abstract B self();

And then override it in the leaf subclass:

@Override
RabbitBuilder self() { return this; }

The issue with doing it that way is that although it's more type-safe, the subclass can return something other than this. Basically, either way, the subclass has the opportunity to do something wrong, so I don't really see much of a reason to prefer one of those approaches over the other.

Subclassing builder pattern with a twist in Java

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();

Java: Abstract class with builder pattern

As there are no instances of A (being an abstract class), an A builder can only build instances of some none-abstract subclass of A. Having a builder at the level of an abstract class typically lets the builder decide which concrete subclass of A to instantiate, depending on parameters collected in the building process.

The idea behind that approach is that the caller isn't interested in the concrete class, just in the fact that it's an A subclass, and the builder is free to provide the instance that best suits the building request.

If your situation is different, in that the user wants to decide on the resulting class, then you'd create multiple builders, and maybe have them inherit common parts from an (abstract) parent builder. But in such a situation, ask yourself whether using a builder has enough benefit over directly using a constructor to warrant the additional boilerplate code. And with constructors, you immediately get inheritance for free.

The fact that something like a "builder pattern" exists doesn't imply that it fulfills your requirements.

So, to summarize the options I see:

  • Have a builder at the A level that decides (in the build() method) which subclass to instantiate (if your users aren't interested in the concrete class, just "any A implementation"),
  • Have multiple builders, one for each subclass. To avoid code repetition, they can inherit from an abstract builder at the A class level. This gives complete control over the resulting type to the user.
  • Ignore the builder pattern, and use plain old constructors.

Java Builder pattern with inheritance

Modify the superclass's builder to use an F-bound (aka the Curiously Recurring Template Pattern).

public interface SuperClassBuilderInterface<SELF extends SuperClassBuilderInterface<SELF>> {
SELF withS1(String s1);
// etc.
Superclass build();
}

Then you have:

class SuperClassBuilder<SELF extends SuperClassBuilder<SELF>> implements SuperClassBuilderInterface<SELF>

interface ABuilderInterface<SELF extends ABuilderInterface<SELF>> extends SuperClassBuilderInterface<SELF>

class ABuilder extends SuperClassBuilder<ABuilder> implements ABuilderInterface<ABuilder>

Note that the implementation of SuperClassBuilder must contain unchecked casts of the form return (SELF)this;. The type system is theoretically powerful enough to not need this, but the resulting encoding would probably be very ugly (see this) and it's likely not worth it.

EDIT: This is what @shmosel meant

Subclassing a subclass of a (generic) builder

You should replace public static class BuilderSubclass<T extends BuilderSubclass<T>> extends Builder<BuilderSubclass<T>> with public static class BuilderSubclass<T extends BuilderSubclass<T>> extends Builder<T>.

Extending classes using Builder pattern

You can solve your problem with generics, although it does require creation of an abstract superclass. Lurking on this site has taught me that inheriting from a concrete class is widely considered to be evil.

public abstract class AbstractA {
protected String s;
protected int i;
protected AbstractA() {
}
protected abstract static class ABuilder<T extends AbstractA, B extends ABuilder<T,B>> {
protected T object;
protected B thisObject;
protected abstract T getObject(); //Each concrete implementing subclass overrides this so that T becomes an object of the concrete subclass
protected abstract B thisObject(); //Each concrete implementing subclass builder overrides this for the same reason, but for B for the builder
protected ABuilder() {
object = getObject();
thisObject = thisObject();
}
public B withS(String s) {
object.s = s;
return thisObject;
}
public B withI(int i) {
object.i = i;
return thisObject;
}
public T build() {
return object;
}
}
}

Once you have your abstract class together, you just extend it as many times as you need, overriding the abstract methods in the builder to return the type of object you need.

public final class ConcreteA extends AbstractA {
private String foo;
protected ConcreteA() {
}
public static final class Builder extends AbstractA.ABuilder<ConcreteA,Builder> {
@Override protected ConcreteA getObject() {
return new ConcreteA();
}
@Override protected Builder thisObject() {
return this;
}
public Builder() {
}
public Builder withFoo(String foo) {
object.foo = foo;
return this;
}
}
}

Then...
ConcreteA baz = new ConcreteA.Builder().withFoo("foo").withS("bar").withI(0).build();

Subclassing abstract class in a builder pattern?

PayloadA and PayloadB can extend Payload as shown below:

public abstract class Payload {

private long createTimestamp;
private String key;
// some other fields are here
// getters and setters here
}

public class PayloadA extends Payload {
//add existing code
}
public class PayloadB extends Payload {
//add existing code
}

private void process(Payload payload) {

//Depending upon the object passed, fields will be set for A or B

payload.setCreateTimestamp(ADD_DATA1);
payload.setKey(ADD_DATA2);
//set other fields

//if(payload instanceof PayloadA) {
//payloadA
//}
}

How can I figure out whether payload is PayloadA or PayloadB
inside process()?

You can find that using instanceof like payload instanceof PayloadA as shown above. But, in general, it is not a good idea to code using of instanceof checks, so don't prefer to use it unless it can't be avoided.

Should I have two different builders here or one big builder here
doing everything?

As per your provided code above, the fields are quite PayloadA and PayloadB different, so better to keep separate beans and respective builders.

UPDATE: I need to figure out what type of payload it is and basis on
that I need to set values for key variable?

Inside setKey() will be called on the object type passed to the process(Payload payload) (polymorphism, one of the fundamental principles of OOP) i.e., if you pass PayloadA object from run() method, setKey() on PayloadA object will be called. To summarise, you don't need instanceof checks at all for this. It is upto your requirement where do you want to set the Key, it could be inside process() method (if you have some other dependencies to generate the key) or it could be done as suggested by @Roberto



Related Topics



Leave a reply



Submit