Hero Hamada
Hero Hamada

Reputation: 55

Using a Builder Pattern when a multiple classes inherits a single abstract class

I am building web app with two entities :

  1. Manga - id, title, releaseDate, coverId, genres, authors, volumes etc
  2. Volume of Manga - id, title, releaseDate, coverId, isbn, pages etc

These two classes inherit from the abstract class Book. the Book class will have common variables for both classes: id, title, releaseDate, coverID;

And I am using Pattern Builder to create Manga and Volume objects. But When I am trying to setDescription I am getting this error:

        Manga manga = (Manga) new Manga.Builder().setID(id)
                                     .setTitle(title)
                                     .setCoverID(id)
                                     .setDescription() //Cannot resolve method 'setDescription' in 'Builder'
                                     .build();

Book class:

public abstract class Book<T extends Book> {

public final Long id;
public final String title;

protected Book(final Builder<T> builder) {
    this.id = builder.id;
    this.title = builder.title;
}

public abstract static class Builder<T> {
    private Long id;
    private String title;

    public Builder<T> setID(Long id) {
        this.id = id;
        return this;
    }

    public Builder<T> setTitle(String title) {
        this.title = title;
        return this;
    }

    public abstract T build();
}

My Manga class:

public class Manga extends Book<Manga> {

private final String description;

protected Manga(Builder builder) {
    super(builder);
    this.description = builder.description;
}

public static class Builder extends Book.Builder<Manga> {
    
    private String description;

    public Builder setDescription(String description) {
        this.description = description;
        return this;
    }

    @Override
    public Manga build() {
        return new Manga(this);
    }
}

Or is there an even better solution?

Thanks.

Upvotes: 0

Views: 456

Answers (1)

Daniel Rafael Wosch
Daniel Rafael Wosch

Reputation: 1064

This here should work:

package de.dwosch;

public abstract class Book {

    public final Long id;
    public final String title;

    protected Book(final Builder<?> builder) {
        this.id = builder.id;
        this.title = builder.title;
    }

    public abstract static class Builder<T extends Builder<T>> {
        private Long id;
        private String title;

        public T id(Long id) {
            this.id = id;
            return me();
        }

        public T title(String title) {
            this.title = title;
            return me();
        }

        public abstract T me();
        public abstract Book build();
    }
}

And then

package de.dwosch;

public class Manga extends Book {

    private final String description;

    protected Manga(Builder builder) {
        super(builder);
        this.description = builder.description;
    }

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

        private String description;

        public Builder description(String description) {
            this.description = description;
            return this;
        }

        @Override
        public Builder me() {
            return this;
        }

        @Override
        public Manga build() {
            return new Manga(this);
        }
    }
}

Usage

    Manga manga = new Manga.Builder().description("test")
            .title("title")
            .build();

I have already implemented this pattern several times. Joshua Bloch writes about it in his book Effective Java (great Book btw).

If you need further information on this let me know.

Btw: Personal preference - setter methods without set on the builder flow. Looks 'cleaner' :)

Upvotes: 1

Related Questions