3

What I'm trying to do is create a class (Square) that uses a Builder pattern, and then extend this class as an inner class (MyCube) inside the Object where it's needed (DrawMyCube).

For reasons that are a bit to complex to get into it's preferred to extend these as inner classes (references to local variables).

I've tried to make the example as simple as possible because the real use case is too complex to use on here:

public abstract class Square {
    protected Integer length;
    protected Integer width;

    public abstract static class Builder {
        protected Integer length;
        protected Integer width;

        public abstract Builder length(Integer length);
        public abstract Builder width(Integer width);
    }

    protected Square(Builder builder) {
        this.length = builder.length;
        this.width = builder.width;
    }
}

Now I need to extend and use this in here:

public class DrawMyCube {
    private String myText;
    private Integer height;
    private String canvas;
    private MyCube myCube;

    public DrawMyCube(String canvas) {
        this.canvas = canvas;
        myCube = new MyCube.Builder().length(10).width(10).text("HolaWorld").build();
    }

    public void drawRoutine() {
        myCube.drawMe(canvas);
    }

    protected class MyCube extends Square {
        protected String text;

        public static class Builder extends Square.Builder{
            protected String text;

            public Square.Builder length(Integer length) {this.length = length; return this;}
            public Square.Builder width(Integer width) {this.width = width; return this;}
            public Square.Builder text(String text) {this.text = text; return this;}
        }

        protected MyCube(Builder builder) {
            super(builder);
            this.text = text;
        }

        protected void drawMe(String canvas) {
            canvas.equals(this);
        }
    }
}

However the problem is the static Builder in the inner class:

The member type Builder cannot be declared static; static types can only be declared in static or top level types.

Alternatively, I can create the inner class MyCube as a regular class, but then the problem becomes that I can not refer back to anything inside the DrawMyCube class (and in the real use case there are many references to various of these).

Paul Bellora
  • 54,340
  • 18
  • 130
  • 181
uncrase
  • 644
  • 1
  • 8
  • 16

1 Answers1

0

Static nested classes can only be declared in a static context, which is why you're seeing that compiler error. Just declare your Builder class adjacent to MyCube (or anywhere else in static context, it doesn't matter). For example:

public class DrawMyCube {

    protected class MyCube extends Square { }

    public static class MyCubeBuilder extends Square.Builder { }
}

Note that the builder will need a reference to the outer DrawMyCube instance in order to instantiate a new MyCube. For this reason you might just make it an inner (non-static) class of MyCube:

public class DrawMyCube {

    protected class MyCube extends Square { }

    public class MyCubeBuilder extends Square.Builder { }
}

As you can see I still declared it adjacent to MyCube because having a builder as an inner class to what it builds just doesn't make sense.

Edit: As you mentioned, a simple alternative would be to make MyCube static:

public class DrawMyCube {

    protected static class MyCube extends Square {

        public static class Builder extends Square.Builder { }
    }
}

Because honestly there isn't a huge benefit to using inner classes - just the implicit outer instance reference - and this would let you keep your existing hierarchy and naming conventions. You can easily implement the reference to the outer DrawMyCube yourself - it just takes a little more code.


As a side note you're probably going to want to use generics to implement your builder pattern, for example an abstract Builder<T> where an implementation builds an instance of T. As it is, there won't be a way to narrow down what your deriving builder classes produce. Here's a sketch of what I'm hinting at:

abstract class Square { }

abstract class SquareBuilder<T extends Square> { }

class MyCube extends Square { }

class MyCubeBuilder extends SquareBuilder<MyCube> { }
Paul Bellora
  • 54,340
  • 18
  • 130
  • 181