Returning an inherited class instead of a superclass to a method override

I have a specific class structure that looks something like this:

class Parent {
    public Parent(int property) { /* use property */}
}
class Son extends Parent {
    public Son(int parentProperty, String sonProperty) { 
        super(parentProperty);
        /* use son property */ 
    }
}

I would like to create collectors for both of these classes so that:

class ParentBuilder {
    protected int parentProperty;

    public ParentBuilder parentProperty(int parentPropertyValue) {
        parentPropertyValue = parentPropertyValue;
        return this;
    }

    public Parent build() {
        return new Parent(parentProperty);
    }
}
class SonBuilder extends ParentBuilder {
    private String sonProperty;

    public SonBuilder sonProperty(String sonProperty) {
        this.sonProperty = sonProperty;
        return this;
    }

    @Override
    public Son build() {
        return new Son(parentProperty, sonProperty);
    }
}

but this causes the following problem:

SonBuilder sonBuilder = new SonBuilder();
sonBuilder.sonProperty("aString").build(); // this works and creates Son
sonBuilder.sonProperty("aString").parentProperty(1).build(); // this works and creates Parent instead of Son
sonBuilder.parentProperty(1).sonProperty("aString").build(); // this doesn't work

I understand that I am nitpicking, and this can be solved simply by not returning this(i.e. without a chain of methods), but I wonder if there is an elegant solution.

change

The word "elegant" seems to be a source of some confusion.

By “elegant,” I mean a solution that allows you to bind a method and does not include casting.

+4
source share
5 answers

First point

sonBuilder.sonProperty("aString").parentProperty(1).build();

it works and creates a parent instead of the Son

, parentProperty() a ParentBuilder:

public ParentBuilder parentProperty(int parentPropertyValue) {...

ParentBuilder.build() Parent:

public Parent build() {
    return new Parent(parentProperty);
}

sonBuilder.parentProperty(1).sonProperty("aString").build(); // this doesn't work

, parentProperty() a ParentBuilder.
ParentBuilder, , sonProperty().
.

, .

SonBuilder ParentBuilder, ParentBuilder. :

class SonBuilder {

    private String sonProperty;
    private ParentBuilder parentBuilder = new ParentBuilder();

    public SonBuilder sonProperty(String sonProperty) {
      this.sonProperty = sonProperty;
      return this;
    }

    public SonBuilder parentProperty(int parentPropertyValue) {
      parentBuilder.parentProperty(parentPropertyValue);
      return this;
    }

    public Son build() {
      return new Son(parentBuilder.parentProperty, sonProperty);
    }
}

Son:

SonBuilder sonBuilder = new SonBuilder();
Son son = sonBuilder.sonProperty("aString").parentProperty(1).build();
+5

, build().

return (parentProperty == null) ? new Parent(parentProperty, sonProperty) : new Son(sonProperty);
0

, , :

SonBuilder sonBuilder = new SonBuilder();
Son son1 = sonBuilder.sonProperty("aString").build();
Son son2 = (Son) sonBuilder.sonProperty("aString").parentProperty(1).build();
Son son3 = ((SonBuilder) sonBuilder.parentProperty(1)).sonProperty("aString").build();
0

parentProperty SonBuilder:

@Override
public SonBuilder parentProperty(int parentPropertyValue) {
    super.parentProperty(parentPropertyValue);
    return this;
}

, ( , ) super.parentProperty this. , .

generics:

abstract class AParentBuilder<T extends Parent> {
    protected int parentProperty;

    public AParentBuilder<T> parentProperty(int parentPropertyValue) {
        parentPropertyValue = parentPropertyValue;
        return this;
    }

    abstract public T build();
}

class ParentBuilder extends AParentBuilder<Parent> {
    @Override
    public Parent build() {
        return new Parent(parentProperty);
    }
}

abstract class ASonBuilder<T extends Son> extends AParentBuilder<T> {
    private String sonProperty;

    public ASonBuilder<T> sonProperty(String sonProperty) {
        this.sonProperty = sonProperty;
        return this;
    }
}

class SonBuilder extends ASonBuilder<Son> {
    @Override
    public Son build() {
        return new Son(parentProperty, sonProperty);
    }
}
0

.

SonBuilder extend ParentBuilder, parentProperty(), SonBuilder:

@Override
public SonBuilder parentProperty(int parentPropertyValue) {
   super.parentProperty(parentPropertyValue);
   return this;
}

:

SonBuilder sonBuilder = new SonBuilder();
Son son = sonBuilder.sonProperty("aString").parentProperty(1).build();

parentProperty(1) , SonBuilder.

, .
.
, setProperty , .
: , , Son.
, , .
.

, , , SonBuilder .

0

Source: https://habr.com/ru/post/1688991/


All Articles