Subclassing with Bloch’s Builder pattern

A co-worker of mine recently ran across this post by Eamonn McManus, “Using the builder pattern with subclasses,” and after due consideration, settled on what McManus calls “a shorter, smellier variant.”

Shorter because:

  1. it has only one Builder class per class

Smellier because:

  1. it uses raw types
  2. the builder’s self() method requires an unchecked cast

Frankly, I don’t find the shortness here a compelling argument for the smell, but I also think there’s more shortness to be found in McManus’ design while remaining fragrant. Thus:

class Shape
{
    private final double opacity;

    public double getOpacity()
    {
        return opacity;
    }

    public static abstract class Builder<T extends Shape> {

        private double opacity;

        public Builder<T> opacity(double opacity) {
            this.opacity = opacity;
            return this;
        }

        public abstract T build();
    }

    public static Builder<?> builder() {
        return new Builder<Shape>()
        {
            @Override
            public Shape build()
            {
                return new Shape(this);
            }
        };
    }

    protected Shape(Builder<?> builder) {
        this.opacity = builder.opacity;
    }
}

class Rectangle extends Shape {

    private final double height;
    private final double width;

    public double getHeight()
    {
        return height;
    }

    public double getWidth()
    {
        return width;
    }

    public static abstract class Builder<T extends Rectangle> extends Shape.Builder<T> {
        private double height;
        private double width;

        public Builder<T> height(double height) {
            this.height = height;
            return this;
        }

        public Builder<T> width(double width) {
            this.width = width;
            return this;
        }
    }

    public static Builder<?> builder() {
        return new Builder<Rectangle>()
        {
            @Override
            public Rectangle build()
            {
                return new Rectangle(this);
            }
        };
    }

    protected Rectangle(Builder<?> builder) {
        super(builder);
        this.height = builder.height;
        this.width = builder.width;
    }
}

class RotatedRectangle extends Rectangle {
    private final double theta;

    public double getTheta()
    {
        return theta;
    }

    public static abstract class Builder<T extends RotatedRectangle> extends Rectangle.Builder<T> {
        private double theta;

        public Builder<T> theta(double theta) {
            this.theta = theta;
            return this;
        }
    }

    public static Builder<?> builder() {
        return new Builder<RotatedRectangle>()
        {
            @Override
            public RotatedRectangle build()
            {
                return new RotatedRectangle(this);
            }
        };
    }

    protected RotatedRectangle(Builder<?> builder) {
        super(builder);
        this.theta = builder.theta;
    }
}

class BuilderTest {
    public static void main(String[] args) {
        RotatedRectangle rotatedRectangle = RotatedRectangle.builder()
                .theta(Math.PI / 2)
                .width(640)
                .height(400)
                .opacity(0.5d)
                .build();
        System.out.println(rotatedRectangle.getTheta());
        System.out.println(rotatedRectangle.getWidth());
        System.out.println(rotatedRectangle.getHeight());
        System.out.println(rotatedRectangle.getOpacity());
    }
}

Now, some notes:

  1. Where McManus’ generics are of the self-referential, Builder<T extends Builder<T>> variety (cf. Enum), in mine a Builder<T> builds Ts. Personally I think this will give fewer developers headaches.
  2. My Builders don’t require a self() method; they simply return this.
  3. Like McManus’ preferred design, this one requires two Builders per class, one abstract and one concrete. However, the concrete one is an anonymous inner class, so it’s less obtrusive, and there’s only one “boilerplate” method per class. A little longer than the “smelly” version in that respect, but in my opinion livable.